<?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[Lucca's Blog]]></title><description><![CDATA[Lucca's Blog]]></description><link>https://blog.luccasiau.com</link><image><url>https://substackcdn.com/image/fetch/$s_!LJ_5!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbb3b7dc-d213-41fb-929c-5a6655f5ff76_512x512.png</url><title>Lucca&apos;s Blog</title><link>https://blog.luccasiau.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 13 May 2026 10:01:53 GMT</lastBuildDate><atom:link href="https://blog.luccasiau.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Lucca Siaudzionis]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[lucca@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[lucca@substack.com]]></itunes:email><itunes:name><![CDATA[Lucca Siaudzionis]]></itunes:name></itunes:owner><itunes:author><![CDATA[Lucca Siaudzionis]]></itunes:author><googleplay:owner><![CDATA[lucca@substack.com]]></googleplay:owner><googleplay:email><![CDATA[lucca@substack.com]]></googleplay:email><googleplay:author><![CDATA[Lucca Siaudzionis]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[GraphQL and the beads on a string]]></title><description><![CDATA[And some poorly drawn lines]]></description><link>https://blog.luccasiau.com/p/graphql-and-the-beads-on-a-string</link><guid isPermaLink="false">https://blog.luccasiau.com/p/graphql-and-the-beads-on-a-string</guid><dc:creator><![CDATA[Lucca Siaudzionis]]></dc:creator><pubDate>Sat, 20 Jan 2024 21:18:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!83mI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>&#8220;Your database, backend and the user are all beads on a string.&#8221;</p><p>Dax (<a href="https://twitter.com/thdxr">thdxr</a>)<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p></blockquote><p>Basically:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M6oF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M6oF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 424w, https://substackcdn.com/image/fetch/$s_!M6oF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 848w, https://substackcdn.com/image/fetch/$s_!M6oF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 1272w, https://substackcdn.com/image/fetch/$s_!M6oF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M6oF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png" width="1442" height="274" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:274,&quot;width&quot;:1442,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:31504,&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_!M6oF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 424w, https://substackcdn.com/image/fetch/$s_!M6oF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 848w, https://substackcdn.com/image/fetch/$s_!M6oF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 1272w, https://substackcdn.com/image/fetch/$s_!M6oF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3f186a6-b023-4e54-b449-3731e4fe6dcf_1442x274.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>But normally you&#8217;ll be hosting your backend very closely to your database, making this other piece of art a bit more accurate:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hKro!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hKro!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 424w, https://substackcdn.com/image/fetch/$s_!hKro!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 848w, https://substackcdn.com/image/fetch/$s_!hKro!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 1272w, https://substackcdn.com/image/fetch/$s_!hKro!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hKro!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png" width="1404" height="234" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:234,&quot;width&quot;:1404,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29880,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hKro!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 424w, https://substackcdn.com/image/fetch/$s_!hKro!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 848w, https://substackcdn.com/image/fetch/$s_!hKro!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 1272w, https://substackcdn.com/image/fetch/$s_!hKro!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe13fb9cc-da50-4311-b4c8-4266fddad335_1404x234.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><div><hr></div><h4>A more real case</h4><p>Loading a typical web page requires different pieces of information &#8212; for example, you may be loading the logged-in user&#8217;s profile on the corner, the main content in the center, and other little details around the page. In a typical REST API design, this will often translate to several separate requests, looking like:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!83mI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!83mI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 424w, https://substackcdn.com/image/fetch/$s_!83mI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 848w, https://substackcdn.com/image/fetch/$s_!83mI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 1272w, https://substackcdn.com/image/fetch/$s_!83mI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!83mI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png" width="1398" height="842" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:842,&quot;width&quot;:1398,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:88315,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!83mI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 424w, https://substackcdn.com/image/fetch/$s_!83mI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 848w, https://substackcdn.com/image/fetch/$s_!83mI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 1272w, https://substackcdn.com/image/fetch/$s_!83mI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F680142ce-1374-4d31-8bab-dcbb4d9d922d_1398x842.png 1456w" sizes="100vw"></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>One of the main benefits of GraphQL is that easily enables the client to make a single request specifying all those pieces of data, and the backend stitches them together. The browser would make a single request asking for the user&#8217;s profile, the main content, and the rest &#8212; and the result looks way better:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!09Sc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!09Sc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 424w, https://substackcdn.com/image/fetch/$s_!09Sc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 848w, https://substackcdn.com/image/fetch/$s_!09Sc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 1272w, https://substackcdn.com/image/fetch/$s_!09Sc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!09Sc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png" width="1378" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:386,&quot;width&quot;:1378,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37173,&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_!09Sc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 424w, https://substackcdn.com/image/fetch/$s_!09Sc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 848w, https://substackcdn.com/image/fetch/$s_!09Sc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 1272w, https://substackcdn.com/image/fetch/$s_!09Sc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8df4069d-0b8c-45bc-932a-43edd685cfe5_1378x386.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/subscribe?"><span>Subscribe now</span></a></p><p>Which brings some simplicity to the client and potentially reduces load time, improving your users&#8217; experience.</p><div><hr></div><h4>We can do the same thing anyway</h4><p>While it&#8217;s true that, in the RESTful case, you can make those requests asynchronously, you would on the other hand add significant complexity to the client. That means dealing with independent request failures and all the dependencies between these separate calls.</p><p>You could also define a single REST endpoint that contains all the information to load the page and mimic the GraphQL behavior. But this would just shift the burden of dealing with complexity from the client to the backend. And while that may be viable for simple applications, it would not be in more complex ones.</p><p>In contrast, GraphQL&#8217;s design fits like a glove for this case. There is no need to design solutions to reduce latency, as it was designed specifically to address such cases.</p><div><hr></div><h4>If you&#8217;re curious, why not just try it?</h4><p>This is just one of the many reasons I appreciate GraphQL. Some other advantages are the very, very easy use of GraphQL subscriptions, and how it makes the API contract between frontend and backend explicitly define (some people don&#8217;t like this one though, but I&#8217;m a huge fan).</p><p>Admittedly, GraphQL is <em>quite</em> different and feels weird at first. It may not seem worth spending the effort to &#8220;relearn&#8221; a new way to do core things. But one day I decided to just try it with Apollo and was surprised and how easy it was. So, if you ever feel a bit curious, just give it a shot.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/p/graphql-and-the-beads-on-a-string?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/p/graphql-and-the-beads-on-a-string?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/subscribe?"><span>Subscribe now</span></a></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 purposefully omitted the rest of the Tweet because it has nothing to do with GraphQL (it was about doing things &#8220;on the edge&#8221;). You can here the context <a href="https://twitter.com/thdxr/status/1484346815088451586">here</a>.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Fast, cheap, and good enough]]></title><description><![CDATA[system 1 vs system 2 &#8212; TCP vs UDP &#8212; obviously &#8212; why I&#8217;m not buying a car]]></description><link>https://blog.luccasiau.com/p/fast-cheap-and-good-enough</link><guid isPermaLink="false">https://blog.luccasiau.com/p/fast-cheap-and-good-enough</guid><dc:creator><![CDATA[Lucca Siaudzionis]]></dc:creator><pubDate>Sat, 29 Oct 2022 19:25:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tLPg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Perfection is expensive. Most people know that, and <em>normally</em> act accordingly. The maxed out MacBook costs thousands more than the base model &#8212; and the base model sells more.</p><p>However, that price can sneak up in other ways. I was recently in the market for a new bicycle. Like a normal person, I had my requirements and budget, and found myself in the lucky (or unlucky?) spot of having numerous candidates. Searching for the perfect match was taking me days &#8212; when I realized it could spiral into weeks and months. I immediately went to the store next to me, tested one that was comfortable, and completed my decision. Is it perfect? Who cares.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tLPg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tLPg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tLPg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tLPg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tLPg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tLPg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg" width="526" height="526" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1080,&quot;width&quot;:1080,&quot;resizeWidth&quot;:526,&quot;bytes&quot;:558624,&quot;alt&quot;:&quot;Caption: &#8220;How many bicycles do you see?&#8221;. Photo contains two bicycles, but the angle makes it seem like there is one long, 3-wheeled, item.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Caption: &#8220;How many bicycles do you see?&#8221;. Photo contains two bicycles, but the angle makes it seem like there is one long, 3-wheeled, item." title="Caption: &#8220;How many bicycles do you see?&#8221;. Photo contains two bicycles, but the angle makes it seem like there is one long, 3-wheeled, item." srcset="https://substackcdn.com/image/fetch/$s_!tLPg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!tLPg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!tLPg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!tLPg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F139b8063-5c96-451d-b3b9-f8ba6e61d064_1080x1080.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">How many bicycles do you see?</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/subscribe?"><span>Subscribe now</span></a></p><h4>SYSTEM 1 AND SYSTEM 2</h4><p>Our brain has two systems of thinking, named by Daniel Kahneman and Amos Tversky as &#8220;System 1&#8221; and &#8220;System 2&#8221;. (Their creativity for naming system is as good as mine for naming variables. Or characters in The Sims.)</p><p>System 1 is the fast, automatic thinking. System 2 is the calm, rational type. 1 quickly answers easier queries, and occasionally gets them wrong. 2 takes its time with complex ones, wanting to be correct. Our muscle memory versus our deep focus.</p><p>System 1 is to blame for all our biases. If you ever caught yourself making an assumption or decision you never thought you would, you should blame your System 1. System 2 is less likely to do such a thing because it takes its steps consciously. As such, System 1 gets a bad rap. In <em>Thinking, Fast and Slow</em>, Kahneman goes through a long list of biases caused by System 1 and how to mitigate them. (As a rough summary: the solutions are not quite on improving System 1, but rather on <em>noticing</em> your biases, and using System 2 to consciously make the better judgement.) </p><p>There&#8217;s some nuance to it, however. In the very same book, Kahneman explains System 1 is the reason we&#8217;re alive at all. If there <em>might</em> be a tiger creeping on you for dinner, you don&#8217;t carefully look at the predator to assess danger &#8212; you run. Once your eyes sensor the animal, System 1 immediately makes the decision: &#8220;<em>TIGER!!! RUN!!!!!!!!!!!!</em>.&#8221;<em> </em>You&#8217;ll be perfectly fine if you ran away while there was no tiger. Being wrong in the other way, however, would be a life-ending mistake.</p><p>Hence, even with its flaws, we can thank System 1 for making critical decision fast. It is undoubtedly the hero that saves you from being run over when you&#8217;re crossing the street and a car runs a red light. But that doesn&#8217;t mean you want it making your investment decisions &#8212; you hit up your System 2 for that.</p><div><hr></div><h4>TCP AND UDP</h4><p>TCP is the perfect communication protocol between two computers. Its ritualistic three-way handshake, sequence numbers, and congestion control ensure every message gets delivered, and they get delivered in the order they should. It is the System 2 of way of communicating. UDP is the more free-spirited version. Packets are sent and no time is wasted with guaranteeing they are delivered.</p><p>There&#8217;d be no email without TCP &#8212; messages needs to be <em>perfect</em>. And there&#8217;d be no Netflix without UDP &#8212; streaming needs to be <em>fast</em>.</p><p>Real-life applications are a bit more nuanced, because the choice is not binary between those two. An engineering team can decide to build their own. And in fact, it is typical to for companies to add logic on top of UDP in order to have <em>some</em> guarantees (Netflix might be fine with you fractions of a second of your show, but certainly not minutes of it).</p><p>You design your own protocol because you can&#8217;t have perfection and speed. But you can give up some of the former to get more of the latter. When faced with the limited resource (the acceptable latency), you realize many guarantees don&#8217;t matter <em>that</em> much. So you let go of them &#8212; and your service becomes fast and good enough.</p><div><hr></div><h4>TRADE-OFFS, OBVIOUSLY</h4><p>Evolution led our brains to develop these two decision-making systems. The two imperative communication protocols also represent a similar duality of perfection versus speed. And it seems like a counter-flow to not at least try to mimic that in other situations.</p><p>As with all other things, there&#8217;s no black and white answer and we need to look at the trade-offs of each situation. But I wouldn&#8217;t have spent the time writing this just to state the obvious. My point is even though we may know that, we often forget we know it and overcomplicate things for no reason. Especially in mundane situations &#8212; completely apart from tigers.</p><p>We shouldn&#8217;t agonize over which phone to buy or where to have dinner &#8212; being wrong about that hardly matters. For such decisions, just pick something good enough and move ahead. And when trying to decide something seemingly important at work, just ask yourself what&#8217;s the worst that could happen if you pick an &#8220;incorrect&#8221; option. Getting things done and moving to the next step is worth ten times more than doing the current decision &#8220;optimally.&#8221; (And remember that always relies on the <em>strong</em> assumption that you even know what it truly is the &#8220;optimal.&#8221;)</p><p>More importantly, we shouldn&#8217;t agonize trying to perfectly satisfy requirements to handle every worst case. Doing so will probably be a regretful decision 99% of the time. You may be stoked on the other 1% of cases, but how much of a premium are you paying for those?</p><div><hr></div><h4>WHY I AM NOT BUYING A CAR</h4><p>I live in San Francisco, a city roughly shaped like a 7 miles by 7 miles square. It&#8217;s compact.</p><p>A 20-minute walk radius from home takes me where I usually need to be. My office, grocery stores, most of my friends, park, and some shops and restaurants. Excluding the time I&#8217;m at home, I spend about 80% of my time within that 20-minute walk radius. A 20-minute <em>bike</em> radius takes me everywhere I usually <em>want</em> to be. My favourite restaurant and shops, plenty of parks, and even more friends. 98% of my time away from home is spent within that bike radius.</p><p>And I&#8217;ve thought about buying a car, because that&#8217;s the natural thing to do. Buying a car would get me <em>everywhere</em> I need to be, without dealing with Lyfts or transit schedules. It is the perfect solution for my target of reaching places faster (being generous to cars in the latter).</p><p>But cars are also the shittiest perfect solution. Moreso in SF. They are ridiculously expensive to acquire, maintain, and to park (both in dollars and, more importantly, time spend to find parking). To put these metrics into perspective:</p><ul><li><p>a fantastic e-bike that truly suits most of your needs will cost considerably less than the annual prices of maintaining a car. Even if you get the car for free!</p></li><li><p>parking often takes 10+ minutes to find in SF, and that time can grow like Bitcoin in 2021. If you&#8217;re driving into a busy area, you&#8217;re likely to spend the same amount of time parking than it&#8217;d take to bike.</p></li></ul><p>If 98% of my time away from home is in a 20-minute bike radius, the chance of me wanting a car would be at most 2%.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> And for those 2% of cases that cars the only option, solutions come naturally: Do I need to get somewhere while tired at night? Uber; road trip to Yosemite? Lyft rentals; wind in my hair while flooring a fast car in an empty highway? Turo and beg someone.</p><p>In one of those rare days, the cost of owning a car would, in that specific day, be less than the cost of dealing with the problem &#8212; Uber&#8217;s surge prices at night can be steep.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> But, those occasions are so infrequent. And on the long run, the not buying a car comes out much, much cheaper.</p><p>Solving for the 98% and improvising the 2% is much faster and cheaper than tackling all 100% at once.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/p/fast-cheap-and-good-enough?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/p/fast-cheap-and-good-enough?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/subscribe?"><span>Subscribe now</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>The numbers are more illustrative than accurate. Just think of them as huge vs tiny probability.</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>In some cases of strong surge pricing, renting a city e-bike is clearly the superior choice. When leaving a crowded event in the Chase Center at night, I could have paid a fortune in an Uber and waited 15-20 minutes to be picked up. But baywheels stations are everywhere. So instead I paid $3 and bikes 12 minutes. Way more fun.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Succession: Bear Hugs and Poison Pills]]></title><description><![CDATA[The internet&#8217;s favorite unrelatable family]]></description><link>https://blog.luccasiau.com/p/succession-bear-hugs-and-poison-pills</link><guid isPermaLink="false">https://blog.luccasiau.com/p/succession-bear-hugs-and-poison-pills</guid><dc:creator><![CDATA[Lucca Siaudzionis]]></dc:creator><pubDate>Mon, 25 Oct 2021 03:44:51 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/aab64296-fe36-4e3c-a982-a3f105b8b244_980x491.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I stumbled upon Succession a little over a month ago, and got hooked faster than Kendall tried to bring down his father. That also means I haven&#8217;t felt the old fans&#8217; pain of waiting 2 years for season 3 &#8212; which I empathize with &#8212; and I&#8217;m lucky to have all the content still fresh in my head.</p><p>The writing in Succession is superb. Not just because it&#8217;s uniquely hilarious, and emotional when it needs to be, but also because every character arc just&#8230; makes sense. All the moves seem to follow logical trajectories set up episodes before. One main move that starts at the end of season 1 and goes throughout season 2 is Stewy and Sandy&#8217;s bear hug on Waystar Royco. Now, <em>buckle up</em> and beware of <strong>season 1 and 2 spoilers</strong>, as we explain a bit more deeply one of the major arcs in the show.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lo2H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lo2H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!lo2H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!lo2H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!lo2H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lo2H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif" width="480" height="270" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:270,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3217006,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&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_!lo2H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!lo2H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!lo2H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!lo2H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F3f934a7e-f52a-404d-87dc-f20f8741364c_480x270.gif 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 class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/subscribe?"><span>Subscribe now</span></a></p><h2>What is a Bear Hug?</h2><p>Stewy and Sandy planned an acquisition of Waystar Royco <em>without</em> Logan and the board&#8217;s consent. They are planning to acquire a company that doesn&#8217;t want to be taken over, making this a <em>hostile tak</em>e<em>over</em>. A bear hug is just one way to do that. With this simple, four-step recipe, you can also bear hug any company you want. (You might need a few billion dollars, though.)</p><h4>Step one: Set a purchase value</h4><p>The bear hug is one of the &#8220;nicest&#8221; forms of hostile takeovers because it requires the takers to pay more than the stock is worth. Usually, significantly more to make it a tempting offer. In the show, the most they reveal is that the stock price of Waystar Royco dipped below $130, and the price Kendall mentions in the bear hug is of $140, or about 8% higher than its fair price.</p><p>What is also interesting is that, if traders were to hear of the secret plan, they&#8217;d go ahead and buy Waystar shares, hoping for a profit, and increase its price all the way up to $140. (At least in theory, which often differs from reality.) This would either make the offer less impressive, because the 8% premium would no longer be there, or require the baddies to find more money. That&#8217;s why when Stewy hears of possible leaks because Kendall spilled the beans in the wedding, he pressures him to execute the plan right away, rather than waiting a few days.</p><h4>Step two: Make an offer to the board</h4><p>This is the dramatic moment in which Kendall makes the offer to his father and foolishly tries to pitch how it is better for investors. The board has a fiduciary duty with the shareholders of the company, meaning they have the legal (and ethical, if anyone cares) obligation to do what is best for them. It&#8217;s hard to argue against an offer that is 8% above the stock price of a company that is going downhill.</p><p>Unsurprisingly, Logan says no.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tACj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tACj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!tACj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!tACj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!tACj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tACj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif" width="480" height="270" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:270,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2954876,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tACj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!tACj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!tACj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!tACj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F56197bcc-a1f8-4ed3-aa47-43217cecbdc2_480x270.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Not on this scene, but same energy.</figcaption></figure></div><h4>Step three: Make the offer public</h4><p>As we know, Kendall abandons the plan because of&#8230; uhh&#8230; personal reasons. Nonetheless, Logan&#8217;s refusal doesn&#8217;t shock Stewy and Sandy, who decide to make the offer public. If the board won&#8217;t budge, the shareholders &#8212; the ones who actually get to elect the board &#8212; can pressure them.</p><p>This is pretty standard in bear hugs. When Microsoft <a href="https://www.nytimes.com/2008/02/05/business/worldbusiness/05iht-deal06.1.9750544.html">attempted to bear hug Yahoo</a>, they made their offer public less than 24 hours later. Clearly, the offer wasn&#8217;t quite for the board, but for the people.</p><h4>Step four: ????</h4><p>At this point, anything could happen.</p><p>Maybe the board yields. Maybe the shareholders put the needed pressure and vote for the acquisition. Maybe management gets to put a good enough fight to survive the attempt. In Succession, as of the end of season 2, we don&#8217;t know what happens yet. The Roys have been resisting and stalling, but we don&#8217;t know how much longer they can stand.</p><p>If the company&#8217;s management really doesn&#8217;t want to be taken over, as the Roys don&#8217;t, they can come up with plans to resist the takeover. One famous one used by Netflix and hinted is the show is called &#8220;swallowing the<em> poison pill.&#8221;</em></p><h3>The Poison Pill</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LG5e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LG5e!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!LG5e!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!LG5e!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!LG5e!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LG5e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif" width="480" height="270" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:270,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3083723,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LG5e!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 424w, https://substackcdn.com/image/fetch/$s_!LG5e!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 848w, https://substackcdn.com/image/fetch/$s_!LG5e!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 1272w, https://substackcdn.com/image/fetch/$s_!LG5e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fce8c1605-f7a2-4736-979b-d1be118c1a11_480x270.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>They don&#8217;t get into detail about this on the show, only mentioning it passing, and I don&#8217;t think it will become a major plot point. I&#8217;d love to be wrong. Nonetheless, when Netflix was suffering a bear hug in 2012, it employed this tactic as a defense.</p><p>The official name for Netflix&#8217;s poison pill was the &#8220;shareholder rights plan,&#8221; which is a cute euphemism. However, calling it a poison pill is reasonable because it could potentially damage the company&#8217;s shares just for the sake of avoiding acquisition. It might not be the best idea, but it can definitely be effective.</p><h4>TLDR: Issuing new shares</h4><p>For the takeover to succeed, the acquirer must buy more than 50% of the company&#8217;s shares. If the company adds more shares to the market, then reaching that percentage becomes more difficult. However, who gets to buy the new shares?</p><p>For the company to resist acquisition, they&#8217;d want anyone <em>except the acquirer</em> to buy those shares. Luckily for them, they can enforce that. Usually, the rule also restricts the new shares only to existing shareholders. In order to make that purchase attractive, the new shares are issued at a discount, say, 10% cheaper than the current market rate. The new shares dilute the value of the old shares, hurting literally all the other investors in the company &#8212; making it a tough poison pill to swallow.</p><p>And should those shares be issued? That also depends. In Netflix&#8217;s case, they set their shareholder rights plan to automatically issue new shares the second Carl Icahn (the attempted acquirer) held a single share past his existing 10% stake at the company.</p><h3>After the Survival</h3><p>The poison pill doesn&#8217;t even need to be executed, it just needs to become a real enough threat to make the acquirer give up. And indeed, Carl Icahn gave up on Netflix, which proved to be great for the company. Similarly, Yahoo managed to put a good enough fight to make Microsoft give up on its $45B offer on the company, which successfully lived its downhill trajectory and was <a href="https://www.theverge.com/2021/9/2/22653652/yahoo-aol-acquired-apollo-global-management-private-equity">sold years later for $4.5B</a>.</p><p>In Succession, Logan mentions that Waystar Royco could end up like Kodak, almost worthless. The $140 price was a good offer, and the family would walk away with a lot. So would the shareholders, of course, but they don&#8217;t care.</p><p>We&#8217;ll see what happens in season 3.</p><div><hr></div><p>By the way, I love trying to understand better the arcs in the shows and films I enjoy. It&#8217;s very refreshing to see writers actually research well into making the plot realistic. We in tech are normally not so lucky. That said, I&#8217;m always open to many suggestions of shows and things to look into.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/p/succession-bear-hugs-and-poison-pills/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://blog.luccasiau.com/p/succession-bear-hugs-and-poison-pills/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Classic Problem: Streaming Median]]></title><description><![CDATA[For some reason, this is considered hard on LeetCode]]></description><link>https://blog.luccasiau.com/p/classic-problem-streaming-median</link><guid isPermaLink="false">https://blog.luccasiau.com/p/classic-problem-streaming-median</guid><dc:creator><![CDATA[Lucca Siaudzionis]]></dc:creator><pubDate>Tue, 18 Aug 2020 03:59:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!0nLE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Apparently, this is considered a &#8220;classic&#8221; and &#8220;hard&#8221; interview problem. I don&#8217;t really care about that. But I can say I&#8217;ve definitely been asked this question in interviews (yes, plural).</p><p>Outside of that context, I actually find the problem itself very interesting. So let&#8217;s explore it.</p><h3>Task</h3><p>The task definition is straightforward. We have to design a data structure that supports two operations:</p><ol><li><p>Add a new [integer] number, and</p></li><li><p>Return the <a href="https://en.wikipedia.org/wiki/Median">median</a> of all numbers added <em>so far</em>.</p></li></ol><p>In other words, the task can be summarized to implementing the following:</p><pre><code>class MedianStream {
 public:
  // Constructor
  MedianStream();
  
  // Adds integer value to the stream
  void addNumber(int x);
  
  // Returns median of all numbers seen so far
  double getMedian();
};</code></pre><p><a href="https://gist.github.com/luccasiau/b95c968963961633070b07f6fab64543">[Github gist link]</a></p><p>For fun&#8217;s sake, let&#8217;s <strong>assume that every call to <code>addNumber</code> is immediately followed by a call to <code>getMedian</code></strong>. This makes the problem get closer to its worst-case, and also makes our runtime analysis a bit cleaner.</p><h4>Example</h4><pre><code>MedianStream* medianStream = new MedianStream();
// List is empty

medianStream-&gt;addNumber(10);
// Sorted list is now [10]

medianStream-&gt;getMedian();
// Returns 10

medianStream-&gt;addNumber(20);
// Sorted list is now [10, 20]

medianStream-&gt;getMedian()
// Returns 15

medianStream-&gt;addNumber(0);
// Sorted list is now [0, 10, 20];

medianStream-&gt;getMedian()
// Returns 10</code></pre><div><hr></div><p>I&#8217;ll talk about four different approaches to this problem here. The first two are unequally bad. The last two are &#8220;equally&#8221; good. If you face this problem in an interview (as I have multiple times before), I strongly advise to go with the better ones.</p><h3>Lazy brute force</h3><p>I don&#8217;t like calling approaches lazy, but this one actually deserves it. It is a lazy brute force because it consists of the laziest (in terms of brain-power) implementations of both functions that interest the problem.</p><ul><li><p><code>void addNumber(int x)</code>: Simply append the value <code>x</code> to some list <code>values</code>.</p></li><li><p><code>double getMedian()</code>: Find and return the median of <code>values</code>. How? Sort the whole list and get the median!</p></li></ul><pre><code>class MedianStream {
 public:
  // Constructor
  MedianStream() {
    numValues = 0;
  }
  
  // Adds integer value to the stream
  void addNumber(int x) {
    numValues++;
    values.push_back(x);
  }
  
  // Returns median of all numbers seen so far
  // Assuming this function is not called on empty lists
  double getMedian() {
    // Sort values
    sort(values.begin(), values.end());
    
    // Calculate and return the median
    if (numValues % 2 == 0) {
      return (values[(numValues-1)/2] +
              values[numValues/2])/2.0;
    } else {
      return values[(numValues-1)/2];
    }
  }

 private:
  int numValues;
  vector&lt;int&gt; values;
};</code></pre><p>[<a href="https://gist.github.com/luccasiau/757062e2d023213761e6a321138a84f3">Github gist link</a>]</p><h4>Runtime</h4><p>The runtime of <code>addNumber</code> is great. We&#8217;re just adding a number to the end of a list, so it&#8217;s <code>O(1)</code>.</p><p>The runtime of <code>getMedian</code> sucks. That little call to the <code>sort</code> function is the bottleneck. Remember that sorting a list of <code>N</code> numbers costs <code>O(N log N)</code>. And that&#8217;s <em>per call</em> of <code>getMedian</code>!</p><p>Hence, calling <code>addNumber</code> followed by <code>getMedian</code> <code>N</code> times will lead to a combined runtime of <code>O(N * 1 + N * N log N)</code>, totaling at an unfortunate <code>O(N^2 log N)</code>.</p><p>Not a good way to pass an interview.</p><h3>Brute force (but not lazy)</h3><p>The great Yogi Berra said &#8220;you can observe a lot by just watching.&#8221; Indeed, if you look into what the current implementation of <code>getMedian</code> is doing, you&#8217;ll observe that we only care about one or two values of the list.</p><p>With that in mind, sorting the entire list before accessing one or two positions is not only overkill, but it&#8217;s also costly. If all we want to do is find the <code>k</code>-th smallest element of a list, the <a href="https://en.wikipedia.org/wiki/Quickselect">Quickselect algorithm</a> will give you that answer in linear time. In C++, you could call the function <a href="http://www.cplusplus.com/reference/algorithm/nth_element/">nth_element</a>.</p><p>I&#8217;ll not go into detail for the idea and implementation of those algorithms since they are not the main part of this note. However, I really recommend checking them out. They might come in handy (and they certainly have to me.)</p><h4>Runtime</h4><p>Nothing changed in <code>addNumber</code> from the previous implementation. It still sits at a wonderful <code>O(1)</code>.</p><p>But now the runtime o <code>getMedian</code> sucks less! The one or two runs of the Quickselect algorithm will take linear time (<code>O(N)</code>), which is an improvement from the previous <code>O(N log N)</code>. Again, that&#8217;s <code>O(N)</code> <em>per call</em> of <code>getMedian</code>.</p><p>In the end, <code>N</code> calls of each function (alternating) will total <code>O(N*1 + N*N)</code>, or simply <code>O(N^2)</code>.</p><p>We can do better.</p><div><hr></div><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0nLE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0nLE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0nLE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0nLE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0nLE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0nLE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg" width="484" height="442.40625" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1170,&quot;width&quot;:1280,&quot;resizeWidth&quot;:484,&quot;bytes&quot;:293378,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0nLE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0nLE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0nLE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0nLE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F64a1198b-0505-42ea-a461-cb6585f0fa1d_1280x1170.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><p>This is a picture of my dog, Fox, to serve as break before heading to the next ideas.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.luccasiau.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.luccasiau.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h3>The actual solution</h3><p>Let&#8217;s make Yogi Berra proud and watch a little more.</p><p>Every time we query for the one or two elements needed to find the median, we always query for the &#8220;same&#8221; position in the list. That is, we are always trying to figure out the <em>middle</em> of the list (we are interested in the median, after all.)</p><p>Also, first or second-year CS students learn about basic data structures that let us do insertions while preserving some type of order. The most popular ones are ordered sets and <a href="https://en.wikipedia.org/wiki/Heap_(data_structure)">heaps</a>. Those structures can only efficiently give you the smallest/largest element in a list. If you try to find out the middle element of a set, you&#8217;re gonna have a bad [run]time. Let&#8217;s assume then we can only know the smallest or largest element of a list, and solve the problem with that tool.</p><h4>Finding the middle</h4><p>Forget about the problem setup for a second.</p><p>Say we have a list <code>S</code>. Let&#8217;s split the list in two halves, and put the smaller elements on a list <code>L</code> and the largest at <code>R</code>. If <code>S</code> originally had <code>N</code> elements and <code>N</code> is even, <code>L</code> and <code>R</code> each have <code>N/2</code>. If <code>N</code> is odd, let&#8217;s say <code>L</code> has the smallest <code>(N+1)/2</code> and <code>R</code> has the largest <code>(N-1)/2</code> elements.</p><p><strong>How do we find the median of S?</strong></p><p>If <code>N</code> is odd, the median of <code>S</code> is the smallest <code>(N+1)/2</code>-th element (1-indexed). This is the largest element of <code>L</code>!</p><p>If <code>N</code> is even, the median will be the average of the smallest <code>N/2</code>-th and <code>(N+2)/2</code>-th elements (1-indexed again). In other words, this will be the average of the largest element of <code>L</code> and the smallest element of <code>R</code>.</p><p>Thus, what we need to efficiently find a median is for <code>L</code> to provide us with its largest element quickly, and for <code>R</code> to give us its smallest element. We can simply make <code>L</code> be a max-heap and <code>R</code> be a min-heap.</p><h4>Updating <code>L</code> and <code>R</code></h4><p>Since <code>L</code> and <code>R</code> were defined as the left and right halves of the original list, there are two properties in them we actually care about:</p><ol><li><p>No element in <code>L</code> is greater than an element in <code>R</code>, and</p></li><li><p><code>0 &lt;= size(L) - size(R) &lt;= 1</code>. This is equivalent of the previous definition we used of allocating the elements as a function of <code>N</code>. However, this doesn&#8217;t make us depend on <code>N</code>, which is nice.</p></li></ol><p>Assume those two properties are currently being respected. When a new element <code>X</code> arrives, we want to add it to either <code>L</code> or <code>R</code>, and make sure those properties continue being respected. This is an overview of the algorithm:</p><ul><li><p>If <code>X &gt; max(L)</code>, add it to <code>R</code>. Otherwise, add it to <code>L</code>.</p><ul><li><p>There&#8217;s a corner case to watch out here: if <code>L</code> is empty (as it will be in the beginning of the algorithm), <code>max(L)</code> would be undefined. We handle this case by simply adding <code>X</code> to <code>L</code> when it is empty.</p></li></ul></li><li><p>If <code>size(R) &gt; size(L)</code>, add <code>min(R)</code> to <code>L</code>, and then remove it from <code>R</code>.</p></li><li><p>If <code>size(L) &gt; size(R) + 1</code>, add <code>max(L)</code> to <code>R</code> and remove it from <code>L</code>.</p></li></ul><p>The first bullet point guarantees property 1 is respected. The second and third bullet points are updating the lists in order to enforce property 2 (without breaking 1).</p><p>Note that, just as we expected, we only need to interact with the largest element in <code>L</code> and the smallest element in <code>R</code>. This makes our use of min and max-heaps appropriate.</p><h4>Ok, where&#8217;s the code?</h4><p>Here:</p><pre><code>class MedianStream {
 public:
  // Constructor
  MedianStream() {
    numValues = 0;
  }
  
  // Adds integer value to the stream
  void addNumber(int x) {
    numValues++;
    
    // The algorithm described above
    if (!leftHalf.empty() &amp;&amp; x &gt; leftHalf.top()) {
      rightHalf.push(x);
    } else {
      leftHalf.push(x);
    }
    
    if (rightHalf.size() &gt; leftHalf.size()) {
      leftHalf.push(rightHalf.top());
      rightHalf.pop();
    }
    
    if (leftHalf.size() &gt; rightHalf.size() + 1) {
      rightHalf.push(leftHalf.top());
      leftHalf.pop();
    }
  }
  
  // Returns median of all numbers seen so far
  // Assuming this function is not called on empty lists
  double getMedian() {
    // Handling cases for odd and even numValues
    if (numValues % 2 == 0) {
      return (leftHalf.top() + rightHalf.top())/2.0;
    } else {
      return leftHalf.top();
    }
  }

 private:
  int numValues;
  // This is a max-heap in C++:
  priority_queue&lt;int&gt; leftHalf;
  // This is a min-heap in C++:
  priority_queue&lt;int, vector&lt;int&gt;, greater&lt;int&gt;&gt; rightHalf;
};</code></pre><p>[<a href="https://gist.github.com/luccasiau/e8eb49334c322840696f412b99f2ddf0">Github gist link</a>]</p><p>I heavily used the <a href="http://www.cplusplus.com/reference/queue/priority_queue/?kw=priority_queue">priority_queue</a> structure from C++. Most languages have some default min/max-heap. Coding your own heap is not hard, but why would you do that?</p><h4>Runtime</h4><p>It may feel like we took a step backwards with <code>addNumber</code>. Before, without any thinking whatsoever, we had an <code>O(1)</code> implementation for it. Now, we have these [constant number] of heap pushes and pops. Remember that each of those operations takes <code>O(log N)</code> time. Thus, our new version of addNumber costs us <code>O(log N)</code>.</p><p>We improved <code>getMedian</code> by as much as we possibly could. Its very short implementation is not deceiving. All we do is query for one or two roots of priority queues. Those happen in constant time. Then, this amazing version of <code>getMedian</code> costs&#8230; <code>O(1)</code>.</p><p>After <code>N</code> operations of each of them, we&#8217;ll settle at <code>O(N log N + N * 1)</code>, or simply<code> O(N log N)</code>.</p><p>This is how you pass an interview.</p><h3>Less code and less elegance</h3><p>Don&#8217;t get me wrong, I love elegant solutions like the one above. It&#8217;s nice solving &#8220;complex&#8221; problems using only basic tools. Any introductory course to data structures will teach heaps, and that is literally all you need to solve this &#8220;hard&#8221; problem.</p><p>But I&#8217;m also a competitive programmer. When push comes to shove, I&#8217;d gladly throw away all my finesse if can save some lines or thinking time. Especially if the runtime is unaffected in the process.</p><p>Basically, what I&#8217;m saying is that this problem could be solved by importing a data structure. Yup. Take a look at the Wikipedia page on the <a href="https://en.wikipedia.org/wiki/Order_statistic_tree">Ordered Statistic Tree</a>. It supports:</p><ul><li><p>Insertions of numbers in <code>O(log N)</code>.</p></li><li><p>Finding the <code>k</code>-th smallest number in <code>O(log N)</code> time.</p></li></ul><p>It even feels like it was tailor-made for this problem. In fact, the ordered statistic tree supports even more operations than those two.</p><p>Another data structure that would immediately solve this problem (by supporting the two previous operations in <code>O(log N)</code> time) is the <a href="https://en.wikipedia.org/wiki/Treap">Treap</a>. In my previous experience, it is much easier to understand a Treap than to actually implement one. Be my guest and have fun coding one.</p><h3>Overall</h3><p>This problem can be solved in <code>O(N log N)</code> time for <code>N</code> operations of each kind (alternating). There is a solution I find beautiful, and one that is less so. There are also brute-force solutions, but they are for losers. You&#8217;re not one.</p><p>I believe beauty in problem-solving has a time and a place. This blog is the place for it. I love the fact that this problem can be solved with primitive tools, rather than using complicated ones. When it&#8217;s your turn to solve this problem, feel free to choose the solution you want. I&#8217;m not your dad.</p><p>Just make sure it is fast.</p><p></p><p></p><p></p><p></p>]]></content:encoded></item></channel></rss>