<?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[Why Now]]></title><description><![CDATA[Breaking down complex technologies into simple sentences and attempting to answer "why" these technologies will "now" be used in production. ]]></description><link>https://whynowtech.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!0Z4j!,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%2F6ea113dc-4511-4cda-914c-0c05af9726a5_210x210.png</url><title>Why Now</title><link>https://whynowtech.substack.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 30 Jun 2026 07:42:57 GMT</lastBuildDate><atom:link href="https://whynowtech.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Alex Mackenzie]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[whynowtech@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[whynowtech@substack.com]]></itunes:email><itunes:name><![CDATA[Alex Mackenzie]]></itunes:name></itunes:owner><itunes:author><![CDATA[Alex Mackenzie]]></itunes:author><googleplay:owner><![CDATA[whynowtech@substack.com]]></googleplay:owner><googleplay:email><![CDATA[whynowtech@substack.com]]></googleplay:email><googleplay:author><![CDATA[Alex Mackenzie]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Deterministic Simulation Testing - Antithesis ]]></title><description><![CDATA[The Deterministic Computer]]></description><link>https://whynowtech.substack.com/p/deterministic-simulation-testing</link><guid isPermaLink="false">https://whynowtech.substack.com/p/deterministic-simulation-testing</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Tue, 20 Jan 2026 16:16:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5lEG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg" 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_!5lEG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5lEG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5lEG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5lEG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5lEG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5lEG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg" width="1456" height="628" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:628,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Chaos testing vs. Antithesis&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="Chaos testing vs. Antithesis" title="Chaos testing vs. Antithesis" srcset="https://substackcdn.com/image/fetch/$s_!5lEG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5lEG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5lEG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5lEG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2243e36d-bde5-4c94-87ac-b4e512afd5b7_3000x1294.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></figure></div><p>For those of you that are new here, welcome! I&#8217;m a partner at <strong><a href="https://www.generalcatalyst.com/">General Catalyst</a></strong> focused on AI, infra, cyber, etc., at the earliest stages. You can also find me on X here: <strong><a href="https://x.com/alex__mackenzie">x.com/alex__mackenzie</a></strong>. Thank you to the ~1.6k of you following along &#128516;  <br><br>Oh &amp; if you could do me a favour and engage with this X post, it goes a long way. Enjoy reading!<br></p><div class="twitter-embed" data-attrs="{&quot;url&quot;:&quot;https://x.com/alex__mackenzie/status/2013646180169769022?s=20&quot;,&quot;full_text&quot;:&quot;Wrote a primer on <span class=\&quot;tweet-fake-link\&quot;>@AntithesisHQ</span>'s Deterministic Computer. h/t to <span class=\&quot;tweet-fake-link\&quot;>@yminsky</span> for sharing the blog post that started this adventure &amp;amp; to <span class=\&quot;tweet-fake-link\&quot;>@sniffnsignulls</span> for the help along the way. Enjoy! (link in comments). &quot;,&quot;username&quot;:&quot;alex__mackenzie&quot;,&quot;name&quot;:&quot;Alex Mackenzie&quot;,&quot;profile_image_url&quot;:&quot;https://pbs.substack.com/profile_images/1483731213735149570/LT-IBBur_normal.jpg&quot;,&quot;date&quot;:&quot;2026-01-20T16:13:55.000Z&quot;,&quot;photos&quot;:[{&quot;img_url&quot;:&quot;https://pbs.substack.com/media/G_HoNQxX0AcqBeY.jpg&quot;,&quot;link_url&quot;:&quot;https://t.co/nLFfxeRLuq&quot;}],&quot;quoted_tweet&quot;:{},&quot;reply_count&quot;:1,&quot;retweet_count&quot;:0,&quot;like_count&quot;:1,&quot;impression_count&quot;:2,&quot;expanded_url&quot;:null,&quot;video_url&quot;:null,&quot;belowTheFold&quot;:false}" data-component-name="Twitter2ToDOM"></div><div><hr></div><p>Ever since reading Tristan Hume&#8217;s (if anyone knows Tristan, I&#8217;d love to say hi sometime) piece whilst at Jane Street on <a href="https://blog.janestreet.com/magic-trace/">Magic Trace</a>, I&#8217;ve closely --watch&#8217;d JS&#8217; <a href="https://blog.janestreet.com/">engineering blog</a>. Their bet on OCaml, <a href="https://blog.janestreet.com/advent-of-fpga-challenge-2025/">Advent of FPGA</a>, and Byrne Hobart&#8217;s <a href="https://www.thediff.co/archive/jane-street/">&#8220;Understanding Jane Street&#8221;</a> piece collectively made me rather JS-pilled.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Why Now! 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>So yeah, when I noticed that <a href="https://blog.janestreet.com/getting-from-tested-to-battle-tested/">Jane Street was leading Antithesis&#8217;</a> latest funding round, my ears pricked up. Great infra companies frequently stem from mega-scale software companies: <a href="https://www.google.com/aclk?sa=L&amp;pf=1&amp;ai=DChsSEwiClua_kYSSAxV7l1AGHbH1Lp8YACICCAEQABoCZGc&amp;co=1&amp;ase=2&amp;gclid=Cj0KCQiAsY3LBhCwARIsAF6O6Xj6bOU1fuQSL4AaG1sHjvAmc36M-A4RaYELJAQdY4GPLCb_k_v4VmIaAkgwEALw_wcB&amp;cce=2&amp;category=acrcp_v1_32&amp;sig=AOD64_1M2fbMMbHmTIm9IDYJK_gFQSPnTQ&amp;q&amp;nis=4&amp;adurl=https://www.confluent.io/lp/confluent-kafka-v3/?utm_medium%3Dsem%26utm_source%3Dgoogle%26utm_campaign%3Dch.sem_br.brand_tp.prs_tgt.confluent-brand_mt.xct_rgn.emea_sbrgn.uki_lng.eng_dv.all_con.confluent-general_term.confluent%26utm_term%3Dconfluent%26creative%3D%26device%3Dc%26placement%3D%26gad_source%3D1%26gad_campaignid%3D22075309561%26gbraid%3D0AAAAADRv2c1JzGNXLWafiB_ehXievuivl%26gclid%3DCj0KCQiAsY3LBhCwARIsAF6O6Xj6bOU1fuQSL4AaG1sHjvAmc36M-A4RaYELJAQdY4GPLCb_k_v4VmIaAkgwEALw_wcB&amp;ved=2ahUKEwivoN6_kYSSAxVXTUEAHeG0DVEQ0Qx6BAgSEAE">Confluent</a>/Kafka from LinkedIn, <a href="https://chronosphere.io/">Chronosphere</a>, <a href="https://temporal.io/">Temporal</a>/Cadence from Uber, <a href="https://www.google.com/aclk?sa=L&amp;pf=1&amp;ai=DChsSEwi96te9qISSAxUBl1AGHWr9C0gYACICCAEQABoCZGc&amp;co=1&amp;ase=2&amp;gclid=Cj0KCQiAsY3LBhCwARIsAF6O6XjI-aGFOENMpB8mxh2fz-Fcnmf9T0Tuooc001DCmDG3PNRk8-gpfykaAiZEEALw_wcB&amp;cce=2&amp;category=acrcp_v1_32&amp;sig=AOD64_0BLPngAhIjLHizaATzmK7xWj8DxA&amp;q&amp;nis=4&amp;adurl=https://clickhouse.com/cloud?utm_campaign%3Dgoogle-brand-emea%26utm_source%3Dgoogle%26utm_medium%3Dpaid-search%26utm_source%3Dgoogle.com%26utm_medium%3Dpaid_search%26utm_campaign%3D21862172336_169330245109%26utm_content%3D764403839923%26utm_term%3Dclickhouse_g_c%26gad_source%3D1%26gad_campaignid%3D21862172336%26gbraid%3D0AAAAAocOPCZudhhR9Xd41f0UV71nRnfQ8%26gclid%3DCj0KCQiAsY3LBhCwARIsAF6O6XjI-aGFOENMpB8mxh2fz-Fcnmf9T0Tuooc001DCmDG3PNRk8-gpfykaAiZEEALw_wcB&amp;ved=2ahUKEwj8ydC9qISSAxWzU0EAHS8cOwkQ0Qx6BAgMEAE">ClickHouse</a> from Yandex, <a href="https://www.google.com/aclk?sa=L&amp;pf=1&amp;ai=DChsSEwjg29XCqISSAxWholAGHdOpJr0YACICCAEQARoCZGc&amp;co=1&amp;ase=2&amp;gclid=Cj0KCQiAsY3LBhCwARIsAF6O6XjUdAsNhYLdWgUDlSSTUfiYmqFqgyPCU0TTBPO5BZBjBAPR1Mcyky0aAkDOEALw_wcB&amp;cce=2&amp;category=acrcp_v1_32&amp;sig=AOD64_2SpcUfaeSCqU0hYoUJNFe4QarMIA&amp;q&amp;nis=4&amp;adurl=https://www.cockroachlabs.com/paid/cloud-2-0-brand-2cta-nn/?utm_source%3Dgoogle%26utm_medium%3Dcpc%26utm_campaign%3Dg-search-emea-bofu-brand%26utm_term%3De-cockroachdb-c%26utm_content%3Dlp660564544987%26utm_network%3Dg%26_bt%3D660564544987%26_bk%3Dcockroachdb%26_bm%3De%26_bn%3Dg%26gad_source%3D1%26gad_campaignid%3D20223483498%26gbraid%3D0AAAAADh3qPezE6tDAIQ-IJ5Zv_PlO5XRS%26gclid%3DCj0KCQiAsY3LBhCwARIsAF6O6XjUdAsNhYLdWgUDlSSTUfiYmqFqgyPCU0TTBPO5BZBjBAPR1Mcyky0aAkDOEALw_wcB&amp;ved=2ahUKEwil987CqISSAxU6W0EAHR7KETMQ0Qx6BAgNEAE">CockroachDB</a> from Google, <a href="https://planetscale.com/">PlanetScale</a>/Vitess from YouTube, etc. I suspect great infra companies are also <em>invested in </em>by mega-scale software companies; when the companies are actual users of the infra vs. corp dev shops, of course. This also played out with <a href="https://flox.dev/blog/about-our-series-b/">D. E. Shaw&#8217;s early bet on Flox.</a></p><p>Turns out, elite testing strategies (like the ones Antithesis incorporates) require some pretty interesting eng work. The kinda work that tends to go down well in this blog. Alright, <a href="https://luma.com/bugbash2026">let&#8217;s bash some bugs.</a> </p><div><hr></div><p>As always, we&#8217;ll begin with a definition which we&#8217;ll then break down bit-by-bit: </p><p><a href="https://antithesis.com/">Antithesis</a> uses<strong>, property-based testing, fuzzing, fault-injection </strong>and<strong> deterministic simulation,</strong> rather than traditional software testing methods. It&#8217;s an autonomous testing platform that finds bugs in your software, with perfect reproducibility to help you fix them.</p><p>Antithesis performs each test run in a <strong>simulated environment</strong>, which they provision &amp; manage automatically. This environment contains your entire service architecture, and uses virtualization to simulate all hardware &amp; network components in the system. <a href="https://x.com/ivanburazin/status/2008214196022874165?s=20">The year of the sandbox, anyone?</a> Customer production systems are never involved, so intense <strong>fault-injection</strong> can be performed with no risk of downtime.</p><p>Anyway, we&#8217;re getting a bit ahead of ourselves, let&#8217;s dig in. What&#8217;s so <em>bad</em> about <em>good</em> ole traditional software testing anyway?</p><div><hr></div><p> <strong>The Problem with Traditional Software Testing?</strong></p><p>Traditional software testing is largely comprised of &#8220;unit tests&#8221; and &#8220;integration tests&#8221; (using libraries like <a href="https://pytest.org/">pytest</a>, <a href="https://jestjs.io/">Jest</a>, <a href="https://junit.org/">JUnit</a>, etc). They&#8217;re known as &#8220;example-based testing&#8221;. Many of you will be all too familiar with these variants of testing, buuut for the uninitiated, let&#8217;s look at unit testing. Quickly. </p><p>Unit tests test if a specific &#8220;unit&#8221; of logic does what we expect. Let&#8217;s say we&#8217;ve created a &#8220;sort_number( )&#8221; function that, when given a list of numbers (e.g. [9, 12, 2, 6]), <em>should </em>return: [2, 6, 9, 12] . Oh, and before you all say it, yes I know python comes with sorted( ) out of the box. Anyway, we&#8217;d &#8220;unit test&#8221; this function like so:</p><pre><code># this is the actual function we will test

def sort_number(numbers):
    result = numbers.copy()
    for i in range(len(result)):
        for j in range(i + 1, len(result)):
            if result[j] &lt; result[i]:
                result[i], result[j] = result[j], result[i]
    return result

# the tests

def test_sort_number():
    assert sort_number([9, 12, 2, 6]) == [2, 6, 9, 12]
    assert sort_number([]) == []
    assert sort_number([1]) == [1]
    assert sort_number([5, 5, 5]) == [5, 5, 5]
    assert sort_number([-3, 0, 2, -1]) == [-3, -1, 0, 2]
    assert sort_number([1, 2, 3]) == [1, 2, 3]  # already sorted
    assert sort_number([3, 2, 1]) == [1, 2, 3]  # reverse sorted</code></pre><p>What we&#8217;re doing in our &#8220;test_sort_number( )&#8221; function is <em>manually </em>(this is important)<em> </em>specifying that when we pass a given list (e.g. [9, 12, 2, 6]) into our &#8220;sort_number( )&#8221; function, that it <em>should</em> equal a certain output, in this case, the output should be [2, 6, 9, 12]. If this isn&#8217;t the case, then our unit test fails and we&#8217;ll receive an error.</p><p><em>Anyway</em>, I&#8217;m not really here to explain unit testing to you. But, I am here to <em>assert</em> its flaws. Particularly in distributed systems. Firstly, unit tests are a pain in the ass to write. You are literally hardcoding inputs and outputs. What this also means is that you need to list, via examples, all of the ways in which your function could fail. The problem is, you might not think of example data that covers all failure modes.  </p><p>Wouldn&#8217;t life be easier if we could stipulate the desired end states, or &#8220;properties&#8221;, of our function&#8217;s outputs, and have tests be automatically generated to assure this end state? If this sounds confusing, it really isn&#8217;t, so bare with me. </p><p>For example, one desired end state of our &#8220;sort_number( )&#8221; function could be that our output length should equal our input length. I.e. if we receive an array with three numbers, our function should output an array containing three numbers. Cool, we can generate a bunch of tests to make sure this is the case. Similarly, we want to ensure that our &#8220;sort_number( )&#8221; function&#8217;s output contains the exact same numbers that it receives as an input, just sorted of course. </p><p>This &#8220;property&#8221;-based approach to testing is called, shock horror, &#8220;Property-Based Testing&#8221;, or &#8220;PBT&#8221;, if you wanna look cool in front of your eng homies. Like many of my favourite eng movements (<a href="https://whynowtech.substack.com/p/flox">i.e. Nix</a>), PBT stems from the functional programming community via <a href="https://hackage.haskell.org/package/QuickCheck">Haskell&#8217;s QuickCheck</a>. The primary PBT library in Python is called <a href="https://hypothesis.readthedocs.io/en/latest/">Hypothesis</a>. Let&#8217;s revisit the properties we mentioned we&#8217;d like our &#8220;sort_number( )&#8221; function to have and implement them via Hypothesis. </p><pre><code>from hypothesis import given
from hypothesis.strategies import lists, integers

@given(lists(integers()))
def test_sort_properties(nums):
    result = sort_number(nums)
    
    # Same length
    assert len(result) == len(nums)
        
    # Same elements
    assert sorted(result) == sorted(nums)</code></pre><p>Nice. Now, by using Hypothesis, we will automatically generate input &amp; output data (i.e. example-based tests) at runtime that we previously had to hand write. It&#8217;ll also bias toward edge cases (empty, single element, negative, large numbers, duplicates, etc.). Now I know testing isn&#8217;t necessarily the &#8220;hottest&#8221; category of developer tools, but c&#8217;mon, that is pretty sweet. Antithesis takes this PBT methodology, but <a href="https://antithesis.com/docs/using_antithesis/sdk/">applies it</a> to how your entire system should work. Don&#8217;t stress about this yet, we&#8217;ll return to it.</p><div><hr></div><p><strong>The Challenge With Distributed Systems?</strong></p><p>When you have a distributed system (multiple services, databases, network calls), bugs often depend on precise timing. This is known as a <a href="https://en.wikipedia.org/wiki/Race_condition">race condition</a>. For example, a race condition might only trigger when server A&#8217;s request arrives exactly 3 milliseconds before server B&#8217;s, whilst the database is mid-write, during a network blip. You could literally run your test suite a thousand times and never hit this bug. Sure, us mere mortals can conjure simple unit tests, but something this complex? Tricky. This is why production is a different beast to development / staging environments.</p><p><a href="https://blog.janestreet.com/getting-from-tested-to-battle-tested/">As Doug Patti at Jane Street puts it: </a>&#8220;testing is still hard. It takes time to write good tests, and in any non-trivial system, your tests are an approximation at best. <a href="https://portswigger.net/research/smashing-the-state-machine">In the real world, programs are messy.</a> The conditions programs runs under are always changing: user behavior is unpredictable, the network blips, a hardware failure causes a host to reboot. It&#8217;s inherently chaotic. That&#8217;s the hard thing about developing <a href="https://en.wikipedia.org/wiki/High_availability">HA systems</a>: for all the careful tests that you think to write, there are some things you can only learn by experiencing that chaos. <a href="https://blog.janestreet.com/getting-from-tested-to-battle-tested/">That&#8217;s what it takes to go from merely being tested to being </a><em><a href="https://blog.janestreet.com/getting-from-tested-to-battle-tested/">battle-tested</a></em><a href="https://blog.janestreet.com/getting-from-tested-to-battle-tested/">.&#8221;</a> </p><p>Nice. Now, I should point out that <a href="https://www.browserstack.com/guide/regression-testing">&#8220;regression testing&#8221;</a> (see something bad happen in production &amp; test for it in the future) has been a testing methodology for some time. But it&#8217;d be preferred if, yeno, the bad thing never happened in the first place? We also have some mitigations for distributed systems&#8217; non-determinism like: <a href="https://stackoverflow.com/questions/34524/what-is-a-mutex">locks/mutexes</a>, atomic operations, and message passing, but they can create performance overhead &amp; are still be difficult to reason about in advance of deploying to production.</p><div><hr></div><p><strong>Antithesis - the Deterministic Computer</strong></p><p>Antithesis takes being &#8220;battle-tested up&#8221; several notches from regression testing etc. Per Jane Street: &#8220;The amazing thing that Antithesis does is run your whole system in a <strong>virtual machine</strong> controlled by a completely <strong>deterministic hypervisor</strong>, and then adds a little <strong>manufactured chaos</strong> by interfering with scheduling and networking. It uses this setup to explore many different scenarios, and to discover circumstances where your system might fail.&#8221;. Alright, now this is something for us to unpack &#128516;</p><p>Aware the above sounds complicated, but don&#8217;t fret. The virtual machine part is easy to grok: Antithesis clones your distributed system (e.g. your food delivery app) &amp; runs it on their own servers (vs. your users&#8217;!). It does this as it wants to mimic your system running in production. It can then replicate this system n-many times, across n-many scenarios (we&#8217;ll get to this).  </p><p><em>Most importantly</em>, these virtual machines (&#8220;VMs&#8221;) are controlled by a <em>deterministic hypervisor</em>. This hypervisor ensures that your distributed system has a consistent set of properties. To make this more concrete, let&#8217;s revisit the race condition we described above. When <em>not using</em> Antithesis, our &#8220;normal&#8221; production system may work like so:</p><pre><code>Monday 2pm - Everything works fine:
- Server A request: arrives at 14:00:00.100
- Server B request: arrives at 14:00:00.250 (150ms later)
- Database write: starts at 14:00:00.050, finishes at 14:00:00.120
- Network: stable
Result: &#10003; Works perfectly

Tuesday 9am - Same exact user actions:
- Server A request: arrives at 09:00:00.100
- Server B request: arrives at 09:00:00.103 (3ms later - just unlucky timing!)
- Database write: starts at 09:00:00.098, still running at 09:00:00.103
- Network: small blip causes 5ms delay
Result: &#10007; BUG! Data corruption!

Wednesday 3pm - Trying to reproduce:
- Server A request: arrives at 15:00:00.100
- Server B request: arrives at 15:00:00.180 (80ms later)
- Database write: starts at 15:00:00.095, finishes at 15:00:00.115
- Network: stable
Result: &#10003; Works fine again

</code></pre><p>&amp; herein lies the issue: you know there&#8217;s a bug, but oftentimes you don&#8217;t know what&#8217;s causing it. Was it our network blip? Was it the server request timing? Perhaps it was the presence of both? etc. Hence, the bug becomes difficult to reproduce. Our system is rather inconsistent. Gah!</p><p>Hopefully it&#8217;s now clear why we&#8217;d like for our system to have a guaranteed set of properties. If we can reproduce this 3ms latency and network blip consistently, and each time they&#8217;re present we note that our data corruption bug occurs, then we&#8217;ve likely found the problem. Nice. </p><p>By contrast, using Antithesis&#8217; deterministic hypervisor, our system would run like the below. These are separate runs, but identical. Note - this is an oversimplification, but illustrative. </p><pre><code><code>Monday 2pm - Running Scenario #1 in Antithesis:
- Server A request: arrives at T+0.100
- Server B request: arrives at T+0.250 (150ms later)
- Database write: starts at T+0.050, finishes at T+0.120
- Network: stable
Result: &#10003; Works perfectly

Tuesday 3pm - Replaying Scenario #1 in Antithesis:
- Server A request: arrives at T+0.100 [IDENTICAL]
- Server B request: arrives at T+0.250 (150ms later) [IDENTICAL]
- Database write: starts at T+0.050, finishes at T+0.120 [IDENTICAL]
- Network: stable [IDENTICAL]
Result: &#10003; Works perfectly [IDENTICAL]

Friday 10am - Replaying Scenario #1 in Antithesis:
- Server A request: arrives at T+0.100 [IDENTICAL]
- Server B request: arrives at T+0.250 (150ms later) [IDENTICAL]
- Database write: starts at T+0.050, finishes at T+0.120 [IDENTICAL]
- Network: stable [IDENTICAL]
Result: &#10003; Works perfectly [IDENTICAL]</code></code></pre><p>Nice. As Doug Patti said, based on the determinism that Antithesis gives us, we can &#8220;[use] this setup to explore many different scenarios, and to discover circumstances where your system might fail.&#8221; I.e. Antithesis will clone your distributed system across a number of VMs, and then autonomously start changing certain properties (e.g. 3ms latency could become 3.5ms) and purposefully inject issues like network blips (&#8220;fault injections&#8221;) in order to test your distributed system. Cool. Have you noticed that this autonomous testing is just <a href="https://antithesis.com/docs/using_antithesis/sdk/">property-based testing</a>? The pieces are coming together.</p><p>If your system fails, no worries, Antithesis will help you reproduce the bug and, ultimately, <a href="https://x.com/AntithesisHQ/status/2011852298285158617?s=20">bash it</a>. This readers, is &#8220;Deterministic Simulation Testing&#8221;.</p><div><hr></div><p><strong>How Does This Work? The </strong><em><strong>Thesis</strong></em><strong> Behind Anti</strong><em><strong>thesis</strong></em></p><p>Ok, I think it&#8217;s important to take a breather and acknowledge that you should now get the value prop of Antithesis. That&#8217;s great. But, how on earth does Antithesis <em>actually</em> achieve this determinism that&#8217;s evidently so hard? <a href="https://antithesis.com/blog/deterministic_hypervisor/">Guys, it&#8217;s honestly so smart.</a></p><p>You see, <em>infrastructure always comes with tradeoffs</em>. The miracles that are modern computers (i.e. the servers running production code) are optimised for speed and throughput, <em>not</em> predictability. Whether it&#8217;s CPU schedulers, caching, multi-core parallelism, etc., they&#8217;re doing their darnedest to make your software fast. But, this means that if your system can run 8ms faster on Tuesday vs. Monday, it will. Hence, it&#8217;s non-deterministic.  </p><p>Instead of trying to recreate production&#8217;s chaotic timing (based on actual milliseconds ticking by on a clock), Antithesis creates a controlled environment where time works fundamentally differently. Don&#8217;t worry, you&#8217;re not reading <a href="https://en.wikipedia.org/wiki/Dark_Matter_(Crouch_novel)">Dark Matter</a>, this is simply cool comp sci.</p><p>Time flows in Antithesis not via milliseconds, but by CPU instruction count. Whether it&#8217;s 2:45pm on Tuesday or 5:15am on Monday is irrelevant, instruction number 5,000 is instruction number 5,000. Our new unit of &#8220;time&#8221; (or &#8220;simulated clock&#8221;) removes the variability inherent in production systems.</p><p>This is important, as software applications often make timing-based decisions (timeouts, rate limiting, cache expiration). If your code sees different time values on different runs, it will behave differently. Antithesis&#8217; &#8220;virtual time&#8221; ensures that your code always sees the same values. This took me quite a bit to grok, so let me walk through an <em>incredibly simplified</em> example.</p><pre><code>start = time.now() # gets us the actual time per our computer's clock</code></pre><p>When the above system call is made, Antithesis intercepts it, and instead, converts the instruction count into a virtual time value in milliseconds. Not sure how they actually calculate this conversion, but for simplicity&#8217;s sake, let&#8217;s pretend they divide the count by 100. In this case, instruction count 5,000 <em>always</em> outputs 50 <em>milliseconds</em>. It ultimately converts to milliseconds as our original code (the time.now( ) function) was written to process milliseconds, not instructions.</p><p>Nice. Now, remember the multi-core parallelism I mentioned above? Well, much like our friend &#8220;time&#8221;, it also creates non-determinism issues. Why? Well, once you have multiple cores each processing separate threads (i.e. CPU instructions), these threads can execute in essentially infinite different orders depending on which core happens to run faster at any given nanosecond. Of course, Antithesis has an answer here too.</p><p>Within Antithesis, each instance of the deterministic hypervisor runs on just one physical CPU core (vs., say, 48 cores). This is totally fine, as this isn&#8217;t our production environment, we don&#8217;t need the speed benefits of multi-core processing.  </p><p>Alright, for those folk interested, there&#8217;s <em>a lot </em>more Antithesis does (<a href="https://antithesis.com/blog/deterministic_hypervisor/#deterministic-i%2Fo">e.g. deterministic I/O</a>) to assemble their &#8220;deterministic computer&#8221;, <em>but</em>, I think at this point, you get my drift. The reality with all great infra is that it&#8217;s not a single &#8220;silver bullet&#8221; idea that solves the underlying problem, but a series of micro-optimisations that compound.</p><p>Incredible work team Antithesis, and <a href="https://antithesis.com/blog/2025/series_a/">congrats on your Series A!</a> time.now( ) to get back to work &#128516;</p><div><hr></div><p><em><strong>Disclaimer</strong></em></p><h6><em><strong>Views expressed in &#8220;posts&#8221; (including podcasts, videos, newsletters, substacks and social media) are those of the individual GC personnel who wrote the post or is quoted therein and are not the views of General Catalyst Group Management, LLC, &#8220;GC&#8221;) or its respective affiliates. GC is an investment adviser registered with the Securities and Exchange Commission. Registration as an investment adviser does not imply any special skill or training. The posts are not directed to any investors or potential investors, and do not constitute an offer to sell &#8212; or a solicitation of an offer to buy &#8212; any securities, cryptocurrencies, or any financial instrument or property, and may not be used or relied upon in evaluating the merits of any investment. Additional important information about GC, including Form ADV Part 2A Brochure, is available at the SEC&#8217;s website: </strong></em>http://www.adviserinfo.sec.gov</h6><h6><em><strong>Nothing here should be construed as or relied upon in any manner as investment, legal, tax, or other advice. Any projections, estimates, forecasts, targets, prospects, or opinions expressed in these materials are subject to change without notice and may differ or be contrary to opinions expressed by others. Any charts or figures provided here are for informational purposes only, and should not be relied upon when making any investment decision. Certain information contained in the content has been obtained from third-party sources. While taken from sources believed to be reliable, no one has independently verified such information and there are no representations about the enduring accuracy of the information or its appropriateness for a given situation.</strong></em></h6><h6><em><strong>To the extent any content authored or provided by any GC personnel in this forum or medium makes reference to any company in which any of the funds or vehicles advised by GC have an economic or financial interest, previous or current, none of the information provided or opinions expressed herein are connected in any way with GC&#8217;s business activities, and GC did not provide any information or assistance in the creation of this content.</strong></em></h6><p></p><p></p><p></p><p></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Why Now! 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[Recursive Language Models ("RLMs")]]></title><description><![CDATA[2026 has got itself a new acronym]]></description><link>https://whynowtech.substack.com/p/recursive-language-models-rlms</link><guid isPermaLink="false">https://whynowtech.substack.com/p/recursive-language-models-rlms</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Fri, 09 Jan 2026 16:18:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!REU1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fpbs.substack.com%2Fmedia%2FG-O-_1dWQAQpoJP.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For those of you that are new here, <a href="https://mack.work/#:~:text=Alex%20Mackenzie-,%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF!,-I%27m%20Alex%20Mackenzie">welcome!</a> I&#8217;m a partner at <a href="https://www.generalcatalyst.com/">General Catalyst</a> focused on AI, infra, cyber, etc., at the earliest stages. You can also find me on X here: <a href="https://x.com/alex__mackenzie">x.com/alex__mackenzie</a>. Thank you to the ~1.6k of you following along &#128516; <br><br>If any of you fancy &#8220;liking&#8221; this post&#8217;s X post it <em>genuinely</em> goes a long way in getting this post out there &#128591;&#127995;  </p><div class="twitter-embed" data-attrs="{&quot;url&quot;:&quot;http://x.com/alex__mackenzie/status/2009660122180763997?s=20&quot;,&quot;full_text&quot;:&quot;Wrote a primer on <span class=\&quot;tweet-fake-link\&quot;>@a1zhang</span>'s &amp;amp; <span class=\&quot;tweet-fake-link\&quot;>@lateinteraction</span>'s important work on Recursive Language Models. Enjoy! (link in comments). &quot;,&quot;username&quot;:&quot;alex__mackenzie&quot;,&quot;name&quot;:&quot;Alex Mackenzie&quot;,&quot;profile_image_url&quot;:&quot;https://pbs.substack.com/profile_images/1483731213735149570/LT-IBBur_normal.jpg&quot;,&quot;date&quot;:&quot;2026-01-09T16:14:45.000Z&quot;,&quot;photos&quot;:[{&quot;img_url&quot;:&quot;https://pbs.substack.com/media/G-O-_1dWQAQpoJP.jpg&quot;,&quot;link_url&quot;:&quot;https://t.co/QOWBaaUrCe&quot;}],&quot;quoted_tweet&quot;:{},&quot;reply_count&quot;:1,&quot;retweet_count&quot;:0,&quot;like_count&quot;:0,&quot;impression_count&quot;:4,&quot;expanded_url&quot;:null,&quot;video_url&quot;:null,&quot;belowTheFold&quot;:false}" data-component-name="Twitter2ToDOM"></div><p>My next primer will likely be on <a href="https://antithesis.com/">Antithesis</a> if you feel like subscribing below to keep tabs. Other posts in the proverbial oven include some performance analysis of <a href="https://docs.astral.sh/ruff/">Ruff</a>, Jane Street&#8217;s <a href="https://blog.janestreet.com/magic-trace/">Magic Trace</a>, and a primer on <a href="https://tinygrad.org/">tinygrad</a>. Suggestions are always welcome!</p><div><hr></div><p>Ever since my <a href="https://whynowtech.substack.com/p/post-transformers-hyena-hierarchy">Hyena Hierarchy primer</a> I&#8217;ve been pretty into the research surrounding context optimisation, limits, scaffolding, etc. Largely because, whilst we&#8217;ve continued to make progress here, I still bump into context issues all the time. I often find myself feeling like I need to re-reference a specific file or function in Cursor after a certain period of time. A more &#8220;fun&#8221; example of this issue that I ran into recently was having a Udon recipe described as a Rust object (!). Rust&#8217;s memory safety is great, but I don&#8217;t need it in my noodles (there&#8217;s a sentence I never thought I&#8217;d write).</p><p>It&#8217;s also important to note that there&#8217;s a pretty material difference between a model&#8217;s &#8220;<em>physical&#8221; </em>maximum context window and its maximally <em>effective </em>context window. So we should always be a <em>little </em>skeptical with context window headlines.</p><p>So, over the break, I took note when I saw Alex Zhang&#8217;s &amp; Omar Khattab&#8217;s work doing the rounds on X (<a href="https://arxiv.org/pdf/2512.24601v1">full paper here</a>). Perhaps even more so once I saw just how bullish the Prime Intellect folks were on its implications, describing RLMs as <a href="https://www.primeintellect.ai/blog/rlm">&#8220;The Paradigm of 2026&#8221;</a>. Such is the way with AI these days, on the day I started writing this primer (Jan 7th), Cursor also released their take on <a href="https://cursor.com/blog/dynamic-context-discovery">&#8220;dynamic context discovery&#8221;</a>, which, at a cursory glance, appears to rhyme with some of the thinking behind RLMs.</p><p>So yeah, let&#8217;s start the new year with some research + a new acronym for us to get acquainted with! &amp; if you&#8217;d like to say hi, or have any thoughts, questions, etc., please do drop me a note on X: <a href="https://x.com/alex__mackenzie">https://x.com/alex__mackenzie</a>. Always happy to chat.<br></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Why Now! 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><p><strong>Context Rot</strong></p><p>So, why are we still running into these context issues? Model performance degrades as input (&#8220;context&#8221;) length increases, a phenomenon known as <a href="https://research.trychroma.com/context-rot">&#8220;context rot&#8221;</a>. As Alex Zhang <a href="https://alexzhang13.github.io/">points out</a>, certain experiments refute this claim, but c&#8217;mon, we&#8217;ve all <em>felt</em> it.</p><p>To make this a little less satirical, and a tad more analytical, <a href="https://research.trychroma.com/context-rot">Chroma has done some nice work</a> on charting performance degradation below. But, what actually causes context rot? I&#8217;ll share a few simple explanations with the usual caveat that there are a bunch of smart research directions beyond recursive language models tackling CR.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!muuE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!muuE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png 424w, https://substackcdn.com/image/fetch/$s_!muuE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png 848w, https://substackcdn.com/image/fetch/$s_!muuE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png 1272w, https://substackcdn.com/image/fetch/$s_!muuE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!muuE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png" width="1189" height="790" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:790,&quot;width&quot;:1189,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Claude Sonnet 4, GPT-4.1, Qwen3-32B, and Gemini 2.5 Flash on Repeated Words Task&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="Claude Sonnet 4, GPT-4.1, Qwen3-32B, and Gemini 2.5 Flash on Repeated Words Task" title="Claude Sonnet 4, GPT-4.1, Qwen3-32B, and Gemini 2.5 Flash on Repeated Words Task" srcset="https://substackcdn.com/image/fetch/$s_!muuE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png 424w, https://substackcdn.com/image/fetch/$s_!muuE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png 848w, https://substackcdn.com/image/fetch/$s_!muuE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.png 1272w, https://substackcdn.com/image/fetch/$s_!muuE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff26b7d62-0219-4e03-a33c-3abef05cdceb_1189x790.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>1. Attention Dilution</strong></p><p>The softmax (wrote a <a href="https://open.substack.com/pub/whynowtech/p/post-transformers-hyena-hierarchy?r=c5g0o&amp;selection=1ffa32fa-cdab-45f4-9736-83c1aad516ae&amp;utm_campaign=post-share-selection&amp;utm_medium=web&amp;aspectRatio=instagram&amp;textColor=%23ffffff&amp;bgImage=true">post explaining softmax</a> if you care to dig in) in attention normalizes scores across <em>all</em> tokens. As sequence length grows, attention weights get spread thinner. A token that&#8217;s genuinely important might get 0.3 attention weight in a 500-token context but 0.03 in a 50,000-token context. It&#8217;s worth making sure this point really clicks fyi, models aren&#8217;t &#8220;forgetting&#8221; as such, they&#8217;re distributing probability mass across more candidates.</p><p><strong>2. Positional Encoding Degradation</strong></p><p>Remember, &#8220;Attention&#8221; let models learn which words matter to which, regardless of distance (i.e. their respective positional encodings). The issue here is that most models use positional encodings that were trained on certain sequence lengths (i.e. we have significantly more training data that shows the relationship between tokens at positions 1&#8211;4096 than between tokens at positions 100,000&#8211;104,096). Hence, we get <em>degradation. </em>RoPE (rotary embeddings) and ALiBi help with extrapolation, but there&#8217;s still distributional shift. </p><p><strong>3. Compounding Errors: </strong></p><p>This is a pretty intuitive/obvious one. In autoregressive generation (i.e. models that predict the next token based on ~all prior tokens), small mistakes propagate. More context == more opportunities for the model to slightly mis-weight something, and for those errors accumulate. We can ofc partially attenuate this issue via chain-of-thought reasoning/scratchpadding, but, this adds additional context (see points 1 + 2 above &#129394;). <br><br>++</p><div><hr></div><p><strong>Recursive Language Models</strong></p><p>Ok, so, what are RLMs and how do they help deal with context rot? Oh, and, as a sidenote, using agents to generate UIs to explain technical topics is a total game changer. Would recommend opening up this <a href="https://rlms-gamma.vercel.app/">interactive RLM demo</a> (took 2 mins to spin-up?!) as we walk through the definition. </p><p>As Alex points out, the natural solution to context rot is something along the lines of, &#8220;well maybe if I split the context into two model calls, then combine them in a third model call, I&#8217;d avoid this degradation issue&#8221;. This intuition is the basis for a recursive language model.</p><p>How RLMs roughly work in practice is that we convert our long context (e.g. <a href="https://whynowtech.substack.com/p/turbopuffer">my primer on turbopuffer</a>) into a large python string like so (thank you <a href="https://hex.tech/">Hex</a> for the nice notebook).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FZgc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FZgc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 424w, https://substackcdn.com/image/fetch/$s_!FZgc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 848w, https://substackcdn.com/image/fetch/$s_!FZgc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 1272w, https://substackcdn.com/image/fetch/$s_!FZgc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FZgc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png" width="819" height="259" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:259,&quot;width&quot;:819,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33299,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://whynowtech.substack.com/i/183586487?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FZgc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 424w, https://substackcdn.com/image/fetch/$s_!FZgc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 848w, https://substackcdn.com/image/fetch/$s_!FZgc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 1272w, https://substackcdn.com/image/fetch/$s_!FZgc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d111e7a-defa-4ebf-b06f-7fea6e0d9f1d_819x259.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This python string is now a variable called <code>context</code> that can be processed. Note, so far, our &#8220;Root LM&#8221; hasn&#8217;t actually seen this context, and as a result, can mark itself as safe from context rot. Alex refers to this Root LM as having a &#8220;depth&#8221; equal to 0 (depth=0). As &#8220;recursive&#8221; suggests, we&#8217;ll spin up other LMs that have depths &gt;0, but don&#8217;t worry about this for now. Note that Cursor is doing something similar with their dynamic context discovery whereby they&#8217;re <a href="https://cursor.com/blog/dynamic-context-discovery#1-turning-long-tool-responses-into-files">turning long tool calls into files</a>.</p><p>Important: all our Root LM has &#8220;seen&#8221; thus far is the query (e.g. &#8220;what indexing strategies does turbopuffer use?&#8221;) that we want answered via the context, and the knowledge that <code>context</code> variable exists and that it can be manipulated (the LLM&#8217;s system prompt).</p><p>Next, the Root LM (again, depth=0) &#8220;peeks&#8221; at the context. What this means is it writes some basic python that, for example, helps it 1) determine the length of the context, 2) prints the first 1,500 characters of the context. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!btvb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!btvb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 424w, https://substackcdn.com/image/fetch/$s_!btvb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 848w, https://substackcdn.com/image/fetch/$s_!btvb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 1272w, https://substackcdn.com/image/fetch/$s_!btvb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!btvb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png" width="735" height="139" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:139,&quot;width&quot;:735,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10171,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://whynowtech.substack.com/i/183586487?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!btvb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 424w, https://substackcdn.com/image/fetch/$s_!btvb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 848w, https://substackcdn.com/image/fetch/$s_!btvb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 1272w, https://substackcdn.com/image/fetch/$s_!btvb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55594815-d751-41bf-8ae3-58e89ad77ba5_735x139.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Now, so far, the Root LM has only additionally seen the text&#8217;s first 1,500 characters. Still relatively safe from context rot.</figcaption></figure></div><p><em>Based on the above output,</em> our Root LM may decide to <a href="https://en.wikipedia.org/wiki/Grep">&#8220;grep&#8221;</a> (this is a technical way of saying that we&#8217;ll do a string search) for some additional text related to the query it originally received (remember, this query was: &#8220;what indexing strategies does turbopuffer use?&#8221;). So our string search could be the below. PS - don&#8217;t get intimidated by the <a href="https://www.reddit.com/r/learnprogramming/comments/y95lda/what_exactly_is_regex_used_for/">regex</a> below, it <em>never</em> looks pretty.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Hisp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Hisp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 424w, https://substackcdn.com/image/fetch/$s_!Hisp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 848w, https://substackcdn.com/image/fetch/$s_!Hisp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 1272w, https://substackcdn.com/image/fetch/$s_!Hisp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Hisp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png" width="914" height="189" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:189,&quot;width&quot;:914,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23261,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://whynowtech.substack.com/i/183586487?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Hisp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 424w, https://substackcdn.com/image/fetch/$s_!Hisp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 848w, https://substackcdn.com/image/fetch/$s_!Hisp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 1272w, https://substackcdn.com/image/fetch/$s_!Hisp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F335a7c66-e4dd-4a51-85fc-9be2bee34933_914x189.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>All this is doing is returning back to our Root LM every occurrence of the word &#8220;index&#8221; in the context, as well as the word&#8217;s position plus a 200-character preview around each match. Again, we&#8217;ve progressively added to our Root LM&#8217;s context. The returned object looks roughly like: </p><pre><code>[
  (15234, &#8220;indexing. Ok, so, just like at the library, we use indexes in databases...&#8221;),

  (16102, &#8220;index (remember, the &#8216;asynchronous&#8217; guy) and understand &#8216;ANN&#8217; and &#8216;inverted BM25&#8217;...&#8221;),

  (17845, &#8220;inverted index would look like:\n\n&#8217;rubberized&#8217;: [1, 3]...&#8221;),

]</code></pre><p>With this output, our Root LM can now infer that the indexing section of our turbopuffer primer exists between characters ~15,000-~18,000. It&#8217;s context is updated accordingly. Next is where things get a bit more interesting, as we&#8217;re about to explore depth=1 (i.e. spinning up separate or &#8220;sub&#8221; LMs). See below. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wwVk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wwVk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png 424w, https://substackcdn.com/image/fetch/$s_!wwVk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png 848w, https://substackcdn.com/image/fetch/$s_!wwVk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png 1272w, https://substackcdn.com/image/fetch/$s_!wwVk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wwVk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png" width="829" height="247" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:247,&quot;width&quot;:829,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34896,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://whynowtech.substack.com/i/183586487?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wwVk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png 424w, https://substackcdn.com/image/fetch/$s_!wwVk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png 848w, https://substackcdn.com/image/fetch/$s_!wwVk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.png 1272w, https://substackcdn.com/image/fetch/$s_!wwVk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49b8caa8-ee4e-430d-9a44-6ec4400cad95_829x247.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>Ok, cool, to sum-up: our Root LM has written code to create a new python variable called <code>indexing_section</code> that contains the primer text between characters 15,000-18,000.</p><p>With this in mind, our Root LM calls a sub-LM (depth=1) and asks it to summarise the indexing strategies described in <code>indexing_section</code>. Through doing so, we&#8217;re minimising the amount of context our Root LM receives (e.g. <a href="https://www.primeintellect.ai/blog/rlm#:~:text=The%20two%20most%20important%20changes%20required%20to%20understand%20the%20rest%20of%20the%20article%20are%20(1)%20that%20tools%20beyond%20the%20Python%20REPL%20can%20be%20used%2C%20but%20only%20by%20sub%2DLLMs%3B">perhaps our sub-LM also leverages browser-use</a> to complement what it&#8217;s read in the primer). The sub-LM then passes its final output to the Root LM: </p><pre><code>FINAL(&#8221;turbopuffer uses two main indexing strategies: 1) ANN (Approximate Nearest Neighbor) with SPANN optimization that stores centroids in NVMe cache and posting lists on object storage, and 2) inverted BM25 indexes for text search that map terms to document IDs with relevance scoring.&#8221;)</code></pre><p>So, what the above (hopefully) illustrates that a RLM is a general inference strategy where language models decompose and recursively interact with their input context as a variable. It&#8217;s this input context, and the LM&#8217;s multiple interactions with it, that determines what step the LM will take next vs. some pre-ordained plan (i.e. &#8220;agentic planning&#8221;). It should also be evident that the example query-chain described above requires significantly less context to generate the desired output.</p><div><hr></div><p><strong>So What? What Does This All Mean?</strong></p><p>Well, on the performance side, the RLM team demonstrated that &#8220;an RLM using GPT-5-mini outperforms GPT-5 on a split of the most difficult long-context benchmark[s] [they] got [their] hands on (<a href="https://openreview.net/forum?id=lrDr6dmXOX">OOLONG</a>) by more than double the number of correct answers, and is cheaper per query on average!&#8221;. Nice, seems like we have a pretty material solve for context rot.</p><p>When spelt out like this, RLMs sound kinda trivial though, right? Sure, but it&#8217;s first worth noting that the depth=0 &#8220;peeking&#8221;, &#8220;grepping&#8221; and depth=1 &#8220;summarisation&#8221; steps are strategies the RLM has developed based on its constraints. The RLM wasn&#8217;t instructed to first peek, then grep, etc., nor did it make an initial plan to conduct these steps sequentially. </p><p>For more semantic queries/contexts where the likes of regex fails (regex doesn&#8217;t know <em>what </em>indexing is, it just knows how to search for the literal word &#8220;index&#8221;), RLMs have also identified smart chunking strategies whereby they split the context into multiple &#8220;chunks&#8221;, &amp; then spin-up independent sub-LLMs to process each chunk. Pretty cool. No doubt we&#8217;ll see plenty of other interesting behaviours emerge.</p><p>Now to zoom out, and, as Palmer would say, think about <a href="https://youtu.be/dMhVrYhQUsk?si=GDC0tknaxRVcTzXB&amp;t=1191">the logical end state</a>. Whilst we&#8217;ve yet to see if RLMs get us here (<a href="https://alexzhang13.github.io/blog/2025/rlm/#:~:text=We%20did%20not,of%20inference%20engines.">although multi-threading seems quite doable?</a>), what does it mean to have an infinitely effective context window? Truly full codebase-reasoning (e.g. &#8220;find all the ways this API contract could be violated across these 500 files&#8221;) would be an exciting step. Perhaps we&#8217;re another leap closer to long-running personal assistants, or better yet, Udon recipes without the Rust.</p><p>RLMs also hint that we&#8217;ve found a way for AI to increasingly &#8220;self-manage&#8221; its context which could be rather profound. Will spend more time thinking about what this all means. Excited for 2026. </p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Why Now! 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><p><em><strong>Disclaimer</strong></em></p><h6><em>Views expressed in &#8220;posts&#8221; (including podcasts, videos, newsletters, substacks and social media) are those of the individual GC personnel who wrote the post or is quoted therein and are not the views of General Catalyst Group Management, LLC, &#8220;GC&#8221;) or its respective affiliates. GC is an investment adviser registered with the Securities and Exchange Commission. Registration as an investment adviser does not imply any special skill or training. The posts are not directed to any investors or potential investors, and do not constitute an offer to sell &#8212; or a solicitation of an offer to buy &#8212; any securities, cryptocurrencies, or any financial instrument or property, and may not be used or relied upon in evaluating the merits of any investment.   Additional important information about GC, including Form ADV Part 2A Brochure, is available at the SEC&#8217;s website: </em>http://www.adviserinfo.sec.gov</h6><h6><em>Nothing here should be construed as or relied upon in any manner as investment, legal, tax, or other advice. Any projections, estimates, forecasts, targets, prospects, or opinions expressed in these materials are subject to change without notice and may differ or be contrary to opinions expressed by others. Any charts or figures provided here are for informational purposes only, and should not be relied upon when making any investment decision. Certain information contained in the content has been obtained from third-party sources. While taken from sources believed to be reliable, no one has independently verified such information and there are no representations about the enduring accuracy of the information or its appropriateness for a given situation.</em></h6><h6><em>To the extent any content authored or provided by any GC personnel in this forum or medium makes reference to any company in which any of the funds or vehicles advised by GC have an economic or financial interest, previous or current, none of the information provided or opinions expressed herein are connected in any way with GC&#8217;s business activities, and GC did not provide any information or assistance in the creation of this content.</em></h6><h6></h6>]]></content:encoded></item><item><title><![CDATA[Maze: A Different Type of Security Company]]></title><description><![CDATA[Announcing Our Investment in Maze's Seed; and their Series A led by Theory Ventures]]></description><link>https://whynowtech.substack.com/p/maze-a-different-type-of-security</link><guid isPermaLink="false">https://whynowtech.substack.com/p/maze-a-different-type-of-security</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Wed, 11 Jun 2025 19:31:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/283c562d-b67a-41d5-afa1-8ba14e2cfcb3_1200x630.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>9 months since <a href="https://www.tapestry.vc/">Tapestry VC&#8217;s</a> Seed investment, we&#8217;re delighted to announce <a href="https://mazehq.com/">Maze&#8217;s</a> $25M Series A led by our friends at Theory Ventures.</em></p><p><em>In a few months, Maze has already been deployed across the Fortune 500 and some of the world&#8217;s most sophisticated security teams. But, as <a href="https://www.linkedin.com/posts/harrywetherald_some-news-today-were-delighted-to-launch-activity-7338179315534094336-043P?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAABhTJ2IBWGWH5tPZNqjkpQ1xfceuXi5z54s">Harry Wetherald</a> (Maze&#8217;s CEO) likes to remind me, these are but the early innings.</em></p><p><em><strong>Read the announcement from Harry at Maze <a href="https://www.linkedin.com/posts/harrywetherald_some-news-today-were-delighted-to-launch-activity-7338179315534094336-043P?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAABhTJ2IBWGWH5tPZNqjkpQ1xfceuXi5z54s">here</a> and take Maze for a spin <a href="https://mazehq.com/contact#demo">here</a>.</strong></em></p><p><em>Congratulations Harry, Santiago, Adrian and the Maze team on bringing a bit of &#8220;magic&#8221; back to the cybersecurity industry. </em></p><div><hr></div><p><em>Why does the world need another vulnerability management product?</em></p><p>CVE publish rates continue to increase at an <a href="https://www.cvedetails.com/browse-by-date.php">alarming pace</a>. Concurrently, the average &#8220;time-to-exploit&#8221; (TTE) vulnerabilities has decreased from 207 days in 2021 to a jarring <a href="https://blog.qualys.com/vulnerabilities-threat-research/2023/07/18/part-2-an-in-depth-look-at-the-latest-vulnerability-threat-landscape-attackers-edition">8 days in 2023</a>.  </p><p>This rapid increase barely accounts for advancements in AI. As <a href="https://www.linkedin.com/in/joshbressers?miniProfileUrn=urn%3Ali%3Afsd_profile%3AACoAAACa8GgBe3NCiEt0eHDVKeNFdt5VcvQ1m9g&amp;lipi=urn%3Ali%3Apage%3Ad_flagship3_detail_base%3B6wiia9wbTZGV4c1B3PhG2w%3D%3D">Josh Bressers</a> points out in <a href="https://opensourcesecurity.io/2024/06/03/why-are-vulnerabilities-out-of-control-in-2024/">&#8220;Why are vulnerabilities out of control in 2024?&#8221;</a>: hundreds of millions of pieces of open source software have been released, yet there have been ~250k CVE IDs ever created (?!). There are likely millions of vulnerabilities that can now, or very soon, be discovered at scale with AI. In fact, my friend Sean Heelan recently did just this: <a href="https://sean.heelan.io/2025/05/22/how-i-used-o3-to-find-cve-2025-37899-a-remote-zeroday-vulnerability-in-the-linux-kernels-smb-implementation/">https://sean.heelan.io/2025/05/22/how-i-used-o3-to-find-cve-2025-37899-a-remote-zeroday-vulnerability-in-the-linux-kernels-smb-implementation/</a>. Times they are a changin&#8217;.</p><p>Furthermore, whilst a meaningful percentage of CVEs flagged currently are benign due to <a href="https://blog.qualys.com/vulnerabilities-threat-research/2023/12/19/2023-threat-landscape-year-in-review-part-one">poor PoC exploit code</a>, this example code may be all an LLM needs to accurately reproduce the vulnerability. Auto-exploitation needs to be countered with auto-remediation.</p><p>Whilst (or perhaps because) there are more vulnerabilities than ever, the amount of data describing these vulnerabilities <a href="https://www.infosecurity-magazine.com/news/nist-vulnerability-database/">fell off of a cliff</a> since February 12, 2024 as NIST almost completely halted enriching the world&#8217;s most widely used software vulnerability database (the &#8220;National Vulnerability Database&#8221;). </p><p>Attempts like <a href="https://github.com/cisagov/vulnrichment">Vulnrichment</a> have been made to plug this gap but there is equally an opportunity for private threat intel (e.g. <a href="https://filigran.io/">Filigran</a>) and/or vulnerability management (e.g. <a href="https://mazehq.com/">Maze</a>) players to help fill this void. Regardless, we suspect this event will encourage security practitioners to seek out new sources of vulnerability data, fostering new conversations.</p><div><hr></div><p></p>]]></content:encoded></item><item><title><![CDATA[turbopuffer]]></title><description><![CDATA[cache money]]></description><link>https://whynowtech.substack.com/p/turbopuffer</link><guid isPermaLink="false">https://whynowtech.substack.com/p/turbopuffer</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Mon, 09 Dec 2024 16:34:15 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/22c687c1-587a-40dd-82e9-220715e6c79c_1456x210.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4iGQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4iGQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 424w, https://substackcdn.com/image/fetch/$s_!4iGQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 848w, https://substackcdn.com/image/fetch/$s_!4iGQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 1272w, https://substackcdn.com/image/fetch/$s_!4iGQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4iGQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg" width="1456" height="210" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:210,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;turbopuffer: fast search on object storage&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="turbopuffer: fast search on object storage" title="turbopuffer: fast search on object storage" srcset="https://substackcdn.com/image/fetch/$s_!4iGQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 424w, https://substackcdn.com/image/fetch/$s_!4iGQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 848w, https://substackcdn.com/image/fetch/$s_!4iGQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 1272w, https://substackcdn.com/image/fetch/$s_!4iGQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F652003ec-01cd-4312-a7fa-c0289652aa00_917x132.svg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p></p><p><em>For new folk here, hi, I&#8217;m <a href="https://x.com/alex__mackenzie">Alex Mackenzie</a>, a partner at General Catalyst. I&#8217;d love to hear from any of you reading along: amackenzie@generalcatalyst.com</em></p><p><em>A special thanks to <a href="https://ca.linkedin.com/in/sirupsen">Simon</a> and the cool folk at <a href="https://turbopuffer.com/">turbopuffer</a> for the platform access &amp; for helping me write this. A fun primer to end 2025 on.</em></p><div><hr></div><p>Last year, a well-known (<em>how mysterious</em>) database founder &amp; I were debating investing in another database. Being quite a rare opportunity to ask someone of their ilk, <em>&#8220;what do you look for when investing in databases?&#8221;</em>, I took my shot. Cache hit. </p><p>Perhaps it&#8217;ll seem trite to some of you, but what he said has shaped several of my subsequent investments (e.g. <a href="https://tracebit.com/">Tracebit</a>, <a href="https://flox.dev/">Flox</a>, <a href="https://atlas.security/">Atlas</a>). He said: <em>&#8220;look for companies that &#8216;religions&#8217; can be built around&#8221;</em>. </p><p>I.e. look for companies that stand for something; what they stand for should probably p*ss a few people off. Why? Well, as I stated on Shomik&#8217;s <a href="https://shomik.substack.com/p/20-alex-mackenzie-tapestry-vc-and">podcast</a> (hey Shomik) a year or so ago, <em>&#8220;as degree of opinion goes up, CAC goes down.&#8221; </em>People talk about you because they love ya, or talk about you because they hate ya. Par example, <a href="https://flox.dev/">Flox</a> is built on the &#8220;philosophy&#8221; that is Nix: </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Yk5s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Yk5s!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 424w, https://substackcdn.com/image/fetch/$s_!Yk5s!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 848w, https://substackcdn.com/image/fetch/$s_!Yk5s!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 1272w, https://substackcdn.com/image/fetch/$s_!Yk5s!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Yk5s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png" width="757" height="102" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:102,&quot;width&quot;:757,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19716,&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_!Yk5s!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 424w, https://substackcdn.com/image/fetch/$s_!Yk5s!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 848w, https://substackcdn.com/image/fetch/$s_!Yk5s!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 1272w, https://substackcdn.com/image/fetch/$s_!Yk5s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f51e772-b609-4112-918e-20c1adedeb0c_757x102.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Currently in the data realm there are two &#8220;religions&#8221; that I&#8217;m tracking. <a href="https://skiplabs.io/">Skip</a> (portfolio) is a framework for creating <em>reactive </em>software, which responds in real-time to changing inputs. One way to think about this is &#8220;streaming, without the streams&#8221;. You can only imagine how Kafka zealots respond to such a claim! A primer on <a href="https://skiplabs.io/">Skip</a> will come soon. </p><p>The other religion forming is, as my friend <a href="https://uk.linkedin.com/in/justincormack">Justin</a> recently put it, <em>&#8220;object storage is all you need&#8221;</em>. You should watch his <a href="https://www.youtube.com/watch?v=ei0wwTy6_G4">full presentation</a>, but the tl;dr is that object (or, &#8220;blob&#8221;) storage (think <a href="https://aws.amazon.com/s3/">S3</a>) is having another <a href="https://blog.bitdrift.io/post/bring-your-own-bucket#:~:text=Rise%20of%20the,administration%20and%20operation.">&#8220;moment&#8221;</a>, whereby open table formats (e.g. <a href="https://iceberg.apache.org/">Iceberg</a>), the proliferation of SSDs (vs. HDDs), and compatibility with modern query engines have bestowed blob storage&#8217;s 99.999999999% durability with a little more.. pace. Nice.</p><p>But how does one spot a religion? &amp; better yet, how does one spot <em>&#8220;companies that &#8216;religions&#8217; can be built around&#8221;</em>? In dev tools, infra, cyber, etc., my general learning is that <em>everything</em> washes out in <a href="https://turbopuffer.com/docs">developer docs</a>. Jump into an <a href="https://turbopuffer.com/architecture#:~:text=need%20this%20ASAP.-,Both,-the%20approximate%20nearest">architecture diagram</a> &amp; you&#8217;ll see if a company really stands for something. <a href="https://datarecovery.com/rd/hard-drive-seek-time/">Seek</a> out<em> </em>their<em> explicit trade-offs</em> across speed, cost, usability, etc. Don&#8217;t bother looking at landing pages.</p><p>So, last week, I decided to do some.. washing. I jumped into turbopuffer&#8217;s <a href="https://turbopuffer.com/docs">docs</a> and it became clear that they&#8217;re a disciple of <em>&#8220;only needing&#8221; </em>object storage<em>. </em>Or, as Matt Klein put it, they&#8217;re leveraging the <em><a href="https://blog.bitdrift.io/post/bring-your-own-bucket#:~:text=%E2%80%9Cblob%20store%20first%20architecture.%E2%80%9D">&#8220;blob store first architecture&#8221;</a>. </em>With customers like Notion, Suno, Cursor (<a href="https://whynowtech.substack.com/p/cursor-beyond-the-hype">primer here</a>), Readwise, etc., it seems like this movement has legs.<em> </em>Let&#8217;s dig into &#8220;tpuf&#8221; under the hood and see what we think for ourselves? &lt;(&#176;O&#176;)&gt;</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write technical primers on companies &amp; technologies that I think you should care about.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Ok, as always, let&#8217;s begin by seeing how turbopuffer describes itself. There&#8217;s quite a bit of detail in this description but, don&#8217;t worry, we&#8217;ll break it down piece-by-piece: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!46KY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!46KY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 424w, https://substackcdn.com/image/fetch/$s_!46KY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 848w, https://substackcdn.com/image/fetch/$s_!46KY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 1272w, https://substackcdn.com/image/fetch/$s_!46KY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!46KY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png" width="1160" height="451" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:451,&quot;width&quot;:1160,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:88845,&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_!46KY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 424w, https://substackcdn.com/image/fetch/$s_!46KY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 848w, https://substackcdn.com/image/fetch/$s_!46KY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 1272w, https://substackcdn.com/image/fetch/$s_!46KY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F765dba45-0d38-4d68-b7eb-f92cc4604b5b_1160x451.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p>Cool site, huh. Let&#8217;s tackle <strong>object storage </strong>first. <em>But</em> we&#8217;re going to start counter-intuitively, and <em>briefly</em> touch upon storage hardware (e.g. <a href="https://en.wikipedia.org/wiki/Solid-state_drive">SSDs</a>). </p><p>Why? Well, there are layers-upon-layers of abstractions in data management that can make things quite complex. However, knowing that data is <em>generally</em> stored the same way on a given piece of hardware (irrespective of a high-level abstractions like object storage) gives us a good base to return to.</p><p>So, how is data ultimately stored? Like most things in infra: it depends. SSDs (solid state drives) encode and store data as electrical charges (<a href="https://www.youtube.com/watch?v=E7Up7VuFd8A">watch this</a>); HDDs (hard disk drives) use magnetic &#8220;domains&#8221; to store bits on spinning platters (<a href="https://www.youtube.com/watch?v=wteUW2sL7bc">watch this</a>). </p><p>Ok, back to object storage. There are three primary (aka &#8220;the big three&#8221;) data storage abstractions or &#8220;models&#8221;: 1) file storage, 2) block storage, and 3), object storage. Think of these models as software &#8220;layers&#8221; that enable you (or your software) to reason about, and interface with, data <em>physically</em> contained within storage hardware. </p><p>We&#8217;re all familiar with file storage (even if you don&#8217;t know it yet). In file storage, we create folders (e.g. &#8220;why_now_primers&#8221;), and within these folders (or &#8220;directories&#8221;) files are stored that contain data (e.g. &#8220;subscribers.csv&#8221;):</p><pre><code>File Storage System
&#9492;&#9472;&#9472; why_now_primers/           # Folder (Directory)
    &#9500;&#9472;&#9472; subscribers.csv        # File
    &#9474;   &#9500;&#9472;&#9472; Name, Email, Subscription Date
    &#9474;   &#9500;&#9472;&#9472; Warren Buffett, wb@berkshirehathaway.com, 2023-01-01
    &#9474;   &#9492;&#9472;&#9472; Howard Marks, hm@oaktreecapital.com, 2023-02-01
    &#9492;&#9472;&#9472; readme.txt             # Another File</code></pre><p>Thanks, WB. If you&#8217;re a Mac user you use a specific file system implementation known as APFS, or, <a href="https://en.wikipedia.org/wiki/Apple_File_System">&#8220;Apple File System&#8221;</a> (how, err.. creative). Ok, we understand how this software models our data, but let&#8217;s walkthrough how it interfaces with it. </p><p>Let&#8217;s say we want to open that <em>&#8220;readme.txt&#8221; </em>file up above. When we do so in an app like TextEdit, it makes a &#8220;system call&#8221; (have a <a href="https://whynowtech.substack.com/p/ebpf#:~:text=This%20code%20is%20then%20compiled%20to%20a%20specific%20bytecode%20format%20%2D%20eBPF%20bytecode.%20Post%20being%20compiled%2C%20the%20eBPF%20bytecode%20is%20then%20sent%20to%20the%20kernel%20via%20the%20bpf()%20system%20call.%20System%20calls%20or%20%E2%80%9Csyscalls%E2%80%9D%20are%20the%20APIs%20exposed%20by%20the%20kernel%20which%20allow%20userspace%20applications%20to%20communicate%20with%20the%20kernel.">whole primer</a> on these guys), to the macOS kernel. <em>Then</em>, the kernel hits up APFS and (essentially) says: get me the metadata that maps to this file path: <em>alex/desktop/why_now_primers/readme.txt</em>. </p><p>Buckle up. <em>Included </em>in this metadata is what&#8217;s known as the <a href="https://en.wikipedia.org/wiki/Logical_block_addressing">&#8220;logical block address&#8221;</a> or (&#8220;LBA&#8221;). This is a <em>virtual representation</em> of where readme.txt&#8217;s data is physically stored (the &#8220;physical block address&#8221;). Why bother to virtualise? I asked the same thing. You see, <a href="https://en.wikipedia.org/wiki/Wear_leveling#:~:text=Dynamic%20wear%20leveling%5B,%5D%5B3%5D">for reasons</a> that are beyond the scope of this primer, our data&#8217;s &#8220;PBA&#8221; changes dynamically. So, using our LBA provides us with, you guessed it, a <em>helpful abstraction</em>. </p><p>Nice, I guess we&#8217;ve got file storage down. The thing is&#8230; unbeknownst to you, we also just tackled block storage. <em>Ha!</em> Block storage is literally &#8220;just&#8221; the LBAs we discussed up top. I.e. block storage has no human-friendly abstractions like files &amp; de minimis metadata. </p><p>Just like TextEdit, databases from <a href="https://surrealdb.com/">SurrealDB</a> to <a href="https://rocksdb.org/">RocksDB</a> access LBAs via the file system. <em>However</em>, certain databases like Oracle&#8217;s <a href="https://www.oracle.com/uk/database/real-application-clusters/">Real Application Clusters</a> (&#8220;RAC&#8221;) expose underlying LBAs <em>directly</em> to the database engine, removing the abstraction &amp; hence, ameliorating performance (but creating maintenance overhead, of course). </p><p>The below describes the relationship between file and object storage quite nicely:</p><pre><code>+----------------------------+
|     Application Layer      |
+----------------------------+
            |
            v
+----------------------------+
|    File System (NTFS,      |
|    ext4, HFS+, etc.)       |
+----------------------------+
            |
            v
+----------------------------+
|      Block Storage         |
|                            |
| +--------+  +--------+     |
| | Block  |  | Block  |     |
| |   1    |  |   2    |     |
| +--------+  +--------+     |
| +--------+  +--------+     |
| | Block  |  | Block  |     |
| |   3    |  |   4    |     |
| +--------+  +--------+     |
+----------------------------+
            |
            v
+----------------------------+
|    Physical Storage        |
| (HDD, SSD, Storage Array)  |
+----------------------------+</code></pre><p>Alright, I guess we should probably address object storage now. So, to repeat, object storage is just <em>another</em> model and interface for interacting with data stored on storage hardware like SSDs. So.. what&#8217;s different about it?</p><p>Well, first off, unlike file storage, where data is stored hierarchically (i.e. in a &#8220;tree&#8221; structure), object storage consists of a &#8220;flat&#8221; namespace. This means that we don&#8217;t have folders, but instead, we have a primary key (i.e. a unique identifier) that maps directly to the underlying data, and metadata. Par example: </p><pre><code>why_now_primers/subscribers.csv: {"author": "admin", "description": "Subscriber list"}</code></pre><p>But wait. The &#8220;why_now_primers/subscribers.csv&#8221; key sure looks like a folder? This is where I kept on getting tripped up too! To us, as mere mortals, these keys are made to <em>look like</em> they have hierarchical structures (for legibility reasons), but our system views them as a &#8220;pointer&#8221; to a specific piece of data. Blob storage is an &#8220;unstructured pool&#8221; of data.</p><p>I&#8217;m aware this sounds trivial. <em>But, </em>it has a rather material impact on object storage&#8217;s performance and scalability vs. file storage. <em>Pourquoi? </em>Well, when you store files in a tree structure, the storage system has to follow (or &#8220;traverse&#8221;) the tree, in order to get the data. These trees can get <em>pretty</em> long if you have hundreds of files. Check out the performance hit below. <em>Yikes</em>. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W-3V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W-3V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png 424w, https://substackcdn.com/image/fetch/$s_!W-3V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png 848w, https://substackcdn.com/image/fetch/$s_!W-3V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png 1272w, https://substackcdn.com/image/fetch/$s_!W-3V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W-3V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png" width="1456" height="440" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:440,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:68105,&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_!W-3V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png 424w, https://substackcdn.com/image/fetch/$s_!W-3V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png 848w, https://substackcdn.com/image/fetch/$s_!W-3V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.png 1272w, https://substackcdn.com/image/fetch/$s_!W-3V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F244215f7-a215-4b1f-98bd-b4402d17a8cc_1665x503.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">How cool is it that Claude can generate these charts for us</figcaption></figure></div><p>Ok, we understand why file storage&#8217;s query performance degrades. Why does blob  storage hold up though? Well, the reason I find most instructive<em> </em>is how it handles metadata. </p><p>Let&#8217;s just take a step back for a sec. What is metadata (e.g. a timestamp) but a useful way to help describe, filter, or &#8220;query&#8221; for, some data? So, if we&#8217;re trying to optimise query performance, one way to do it is (surprise, surprise) to optimise how effective our storage system is at adding metadata.</p><p>Now remember, object storage&#8217;s metadata is included in the <em>object itself. </em>This stands in contrast to file storage which stores its metadata in a <em>centralised </em>directory table that&#8217;s <em>shared between</em> folders and files. Hence, as the number of files increases within object storage, there&#8217;s no centralised directory table (i.e. server) that&#8217;s &#8220;overwhelmed&#8221;. Nice.  </p><p>But wait, there&#8217;s more. Object storage also enables you to add <em>custom </em>metadata (e.g. the camera used for a snap) to your data, whereas file storage has a fixed set of metadata that you can add. See the code for creating an S3 bucket below:</p><pre><code>s3.put_object(
    Bucket='my-bucket',
    Key='my-image.jpg',
    Body=open('my-image.jpg', 'rb'),
    Metadata={
        'author': 'A Mack',
        'camera': 'Canon EOS 5D Mark IV',
        'location': 'London init bruv, UK',
        'tags': 'landscape,sunset'
    }
)</code></pre><p>Have a think for a sec why <em>custom metadata</em> can help query performance as the no. of files (or data) grows? Remember, metadata is a filter. So, if we want to query a dataset like every Flickr image ever, and search for photos taken in Europe, having location metadata like &#8220;London&#8221; above helps the cause.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">My next primer will (likely) be on <a href="https://skiplabs.io/">Skip</a> or <a href="https://northflank.com/">Northflank</a>. Subscribe to keep updated.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Nice one, we now have a pretty deep understanding of <s>object storage</s>. Let&#8217;s scrape it off our to-do list. Not to mention storage hardware like <s>SSDs</s> (although there&#8217;s more to come here). Let&#8217;s come back to our turbopuffer definition. Next, we&#8217;re going to tackle <strong>separating storage &amp; compute</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_!7yV-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7yV-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png 424w, https://substackcdn.com/image/fetch/$s_!7yV-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png 848w, https://substackcdn.com/image/fetch/$s_!7yV-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png 1272w, https://substackcdn.com/image/fetch/$s_!7yV-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7yV-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png" width="1141" height="538" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:538,&quot;width&quot;:1141,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:108131,&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_!7yV-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png 424w, https://substackcdn.com/image/fetch/$s_!7yV-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png 848w, https://substackcdn.com/image/fetch/$s_!7yV-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.png 1272w, https://substackcdn.com/image/fetch/$s_!7yV-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2d754bc-0560-4608-ab6c-7bdcc23470a4_1141x538.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>Data is sometimes stored on the same machine that processes it. E.g. on your laptop  you have an HDD (storage) and a CPU (processing). If you use something like a Mac or MSFT Surface (<em>sike!</em>), storage and compute are <em>tightly coupled</em>. If you want to improve your storage, you&#8217;ll likely need to replace your <em>entire machine</em>. This used to be the case with mainframes too.</p><p>However, what if we could <em>decouple </em>this relationship? Then, if we only need more storage, we can add some, vs. also having to add compute capacity (i.e. replace our machine) (i.e &#8220;scale vertically&#8221;).  </p><p>This decoupling would enable us to scale storage and compute up/down to match demand (i.e. add more/less servers) (i.e. &#8220;scale horizontally&#8221;). Sounds a bit like the promise of the cloud, huh? Bingo. </p><p>However, &#8220;back in the day&#8221; having <em>physically separate </em>storage and compute resulted in increased latency, of course. It wasn&#8217;t until improved networking hardware (ethernet to fiber) &amp; software (<a href="https://en.wikipedia.org/wiki/Remote_direct_memory_access#:~:text=In%20computing%2C%20remote%20direct%20memory,in%20massively%20parallel%20computer%20clusters.">RDMA</a> and <a href="https://en.wikipedia.org/wiki/RDMA_over_Converged_Ethernet">RoCE</a>) that made data transfer speeds viable. RDMA &amp; RoCE are beyond the scope of this primer, but are worth digging into. Cool stuff. </p><p>&#8220;Virtualisation&#8221; (i.e. partitioning hardware resources) also made scaling compute flexible, enabling multiple &#8220;VMs&#8221; to run on the same physical server. Want more compute? Cool, &#8220;here&#8217;s another VM&#8221;. Not, &#8220;here&#8217;s another server&#8221;. Nice. </p><p>In many ways, Snowflake or Databricks&#8217; &#8220;religion&#8221; was the separation of storage and compute. And yeno what storage model &#8220;horizontally scales&#8221; particularly well? A <a href="https://aws.amazon.com/s3/#:~:text=Simple%20Storage%20Service%20(Amazon%20S3)">Simple Storage Service</a> indeed.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">I write technical primers on companies &amp; technologies that I think you should care about.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Alright. We&#8217;re doing well. That&#8217;s <s>object storage</s> and the <s>separation of storage and compute</s> done here. Again, we&#8217;ll go with the slightly counter-intuitive route and tackle some of the more esoteric items like <strong>write-ahead logs</strong> &amp; <strong>asynchronous indexing </strong>prior to talking about tpuf directly and connecting all of these concepts together &lt;(&#176;O&#176;)&gt;</p><p>This stuff sounds hard, but tbh, it&#8217;s kinda easy. I&#8217;m going to get in trouble for saying this, but you can sub out the word &#8220;log&#8221;, for &#8220;queue&#8221;. I.e. they&#8217;re data structures that preserve the order of things. We dealt with queues in my primer on <a href="https://whynowtech.substack.com/p/restate-and-durable-execution">Restate &amp; Durable Execution</a> (isn&#8217;t it cool how all of these topics connect).</p><p>So, when turbopuffer receives some new data, it first &#8220;writes&#8221; this data to a log, prior to writing it to its &#8220;primary storage&#8221; (i.e. &#8220;vanilla&#8221; object storage). Hence, it&#8217;s a <em>write-ahead</em> log. </p><p>For context, I say &#8220;vanilla&#8221; because tpuf&#8217;s write-ahead log (or, &#8220;WAL&#8221;) lives within object storage itself. So, think of it as an <em>another </em>abstraction on top of object storage:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8KJx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8KJx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png 424w, https://substackcdn.com/image/fetch/$s_!8KJx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png 848w, https://substackcdn.com/image/fetch/$s_!8KJx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!8KJx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8KJx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png" width="1456" height="680" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:680,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:151321,&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_!8KJx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png 424w, https://substackcdn.com/image/fetch/$s_!8KJx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png 848w, https://substackcdn.com/image/fetch/$s_!8KJx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!8KJx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F649aa491-ba85-44cf-b2e6-2eb96e95475d_2142x1000.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>Hmm. Why doesn&#8217;t tpuf just write data directly to its primary storage? Remember, all infra comes with trade offs. So, as rosy of a picture as I&#8217;ve painted of object storage, it has its flaws. We won&#8217;t dig into all of these flaws, but something rather important that object storage doesn&#8217;t <em>fully (nuance here)</em> support on its own is &#8220;atomic&#8221; transactions (logs do).</p><p>Writes are considered &#8220;atomic&#8221; when only once <em>all</em> of the related data in a transaction (think <em>both</em> debit and credit operations in a bank transfer) are complete. &#8220;Atomicity&#8221; is pretty important, as otherwise your storage system is prone to &#8220;partial writes&#8221; (think the debit operation happening, but not the credit). Partial writes = &#8220;corrupted&#8221; data. So, turbopuffer navigates this issue with a write-ahead log (or &#8220;WAL&#8221;). Nice job tpuf.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jbbs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jbbs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 424w, https://substackcdn.com/image/fetch/$s_!Jbbs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 848w, https://substackcdn.com/image/fetch/$s_!Jbbs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 1272w, https://substackcdn.com/image/fetch/$s_!Jbbs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jbbs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png" width="795" height="125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:125,&quot;width&quot;:795,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:39622,&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_!Jbbs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 424w, https://substackcdn.com/image/fetch/$s_!Jbbs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 848w, https://substackcdn.com/image/fetch/$s_!Jbbs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 1272w, https://substackcdn.com/image/fetch/$s_!Jbbs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd2f3b476-7d1b-4451-8042-2308b024b32e_795x125.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>There&#8217;s <em>a tonne </em>more we could talk about here (<em>alex@tapestry.vc</em>) but let&#8217;s move onto <strong>asynchronous indexing</strong>. Ok, so, just like <a href="https://en.wikipedia.org/wiki/Dewey_Decimal_Classification#:~:text=The%20Dewey%20Decimal%20Classification%20(DDC)%2C%20colloquially%20known%20as%20the%20Dewey%20Decimal%20System%2C%20is%20a%20proprietary%20library%20classification%20system%20which%20allows%20new%20books%20to%20be%20added%20to%20a%20library%20in%20their%20appropriate%20location%20based%20on%20subject">at the library</a>, we use indexes in databases to speed up our searches (i.e. queries). Think of them as filters. Easy. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QjaW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QjaW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 424w, https://substackcdn.com/image/fetch/$s_!QjaW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 848w, https://substackcdn.com/image/fetch/$s_!QjaW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 1272w, https://substackcdn.com/image/fetch/$s_!QjaW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QjaW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png" width="754" height="89" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68336814-f049-4b66-9f25-82281cabc38d_754x89.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:89,&quot;width&quot;:754,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22863,&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_!QjaW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 424w, https://substackcdn.com/image/fetch/$s_!QjaW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 848w, https://substackcdn.com/image/fetch/$s_!QjaW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 1272w, https://substackcdn.com/image/fetch/$s_!QjaW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68336814-f049-4b66-9f25-82281cabc38d_754x89.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Next, to get your head around &#8220;asynchronous&#8221; do what I did &amp; replace <s>asynchronous</s> with <em>independent</em>. I.e. when we update our index (post writing to the WAL), updating the index doesn&#8217;t hold up any new operations like a new write or query. <em>Independence</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3kSb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3kSb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 424w, https://substackcdn.com/image/fetch/$s_!3kSb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 848w, https://substackcdn.com/image/fetch/$s_!3kSb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 1272w, https://substackcdn.com/image/fetch/$s_!3kSb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3kSb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png" width="740" height="75" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:75,&quot;width&quot;:740,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23983,&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_!3kSb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 424w, https://substackcdn.com/image/fetch/$s_!3kSb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 848w, https://substackcdn.com/image/fetch/$s_!3kSb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 1272w, https://substackcdn.com/image/fetch/$s_!3kSb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d17d6c-4d66-4802-87c9-bb58eef7aeea_740x75.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">if you&#8217;re this far (fair play), you&#8217;ve likely subbed. If not, go on</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Pretty cool that we can now strike: <s>separating storage and compute</s>, <s>object storage</s>, <s>write-ahead logs</s> <em>and </em><s>asynchronous indexing</s> off of our list. There are a few other gnarlier topics within tpuf&#8217;s <a href="https://turbopuffer.com/architecture">architecture</a> that I <em>wasn&#8217;t</em> going to dig into (<em>&#8220;don&#8217;t over-load the reader Alex!&#8221;</em>); but then I remembered&#8230; whilst I&#8217;m grateful for all of you that read along, I honestly write all of this for me first tbh. <em>Sorry!</em></p><p>So, uh.. let&#8217;s touch on a few other items and then I <em>promise </em>we&#8217;ll actually take tpuf for a t-spin and build something cool with it. I have some fun ideas. Ok, back to some tpuf architecture topics below. Rapid fire.    </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0TOo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0TOo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 424w, https://substackcdn.com/image/fetch/$s_!0TOo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 848w, https://substackcdn.com/image/fetch/$s_!0TOo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 1272w, https://substackcdn.com/image/fetch/$s_!0TOo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0TOo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png" width="1456" height="261" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:261,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:111169,&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_!0TOo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 424w, https://substackcdn.com/image/fetch/$s_!0TOo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 848w, https://substackcdn.com/image/fetch/$s_!0TOo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 1272w, https://substackcdn.com/image/fetch/$s_!0TOo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bc19798-7388-4e06-9cc6-ef04e34d926d_1608x288.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Visualise the above using the image below. That &#8220;./tpuf&#8221; is just their API (written in Rust fwiw). <a href="https://www.techtarget.com/whatis/definition/caching#:~:text=Caching%20%2D%2D%20pronounced%20%22cashing%22%20%2D%2D,improving%20application%20and%20system%20performance.">Caching</a> (or &#8220;cache locality&#8221;) is easy, so let&#8217;s not dig into that. NVMe SSDs were new to me, so let&#8217;s linger a bit here. Traditional SSDs use the &#8220;SATA&#8221; bus. Buses (think cables, controllers, protocols, etc) are how hardware like RAM connects to other components like the CPU.  </p><p>The &#8220;SATA&#8221; bus was originally built for HDDs, so it&#8217;s been knockin&#8217; around for a bit. &amp; more importantly, it isn&#8217;t <em>optimised, </em>for SSDs (was never really built for &#8216;em). NVMe SSDs, however, are capable of using the more performant &#8220;PCIe&#8221; bus. These SSDs hit GA on AWS <a href="https://aws.amazon.com/about-aws/whats-new/2018/05/announcing-general-availability-of-amazon-ec2-bare-metal-instances/?utm_source=chatgpt.com#:~:text=As%20a%20new%20instance%20size%20belonging%20to%20the%20I3%20instance%20family%2C%20bare%20metal%20I3%20instances%20have%20the%20same%20characteristics%20as%20other%20instances%20in%20the%20family%2C%20including%20NVMe%20SSD%2Dbacked%20instance%20storage">in 2018</a> (h/t Simon). Hence, tpuf&#8217;s cache gets a nice performance bump.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!55pI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!55pI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png 424w, https://substackcdn.com/image/fetch/$s_!55pI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png 848w, https://substackcdn.com/image/fetch/$s_!55pI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png 1272w, https://substackcdn.com/image/fetch/$s_!55pI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!55pI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png" width="1077" height="375" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:375,&quot;width&quot;:1077,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24477,&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_!55pI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png 424w, https://substackcdn.com/image/fetch/$s_!55pI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png 848w, https://substackcdn.com/image/fetch/$s_!55pI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.png 1272w, https://substackcdn.com/image/fetch/$s_!55pI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1198927-0214-42cc-a041-82d9cb3d4f50_1077x375.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>Ok, next. Let&#8217;s revisit our index (remember, the &#8220;asynchronous&#8221; guy) and understand &#8220;ANN&#8221; and &#8220;inverted BM25&#8221; indices. I bloody love all of the optimisation work this team has done (&amp; shared). <em>Religion building washes out in the developer docs</em>! </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0lbg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0lbg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 424w, https://substackcdn.com/image/fetch/$s_!0lbg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 848w, https://substackcdn.com/image/fetch/$s_!0lbg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 1272w, https://substackcdn.com/image/fetch/$s_!0lbg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0lbg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png" width="786" height="99" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:99,&quot;width&quot;:786,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:31443,&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_!0lbg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 424w, https://substackcdn.com/image/fetch/$s_!0lbg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 848w, https://substackcdn.com/image/fetch/$s_!0lbg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 1272w, https://substackcdn.com/image/fetch/$s_!0lbg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbb85386-bd3e-461f-a8c9-49bc17c99c7b_786x99.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>You might recall &#8220;nearest neighbours&#8221; from your probability classes. Let&#8217;s do a quick refresher. Imagine we have a query vector (e.g. an image encoded as a point in a multi-dimensional space) (e.g. a picture of <a href="http://niobium c_3">these Niobium C_3s</a>), we might want our website to <em>recommend </em>&#8220;related products&#8221;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1Q9l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1Q9l!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png 424w, https://substackcdn.com/image/fetch/$s_!1Q9l!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png 848w, https://substackcdn.com/image/fetch/$s_!1Q9l!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png 1272w, https://substackcdn.com/image/fetch/$s_!1Q9l!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1Q9l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png" width="1456" height="436" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:436,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:901451,&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_!1Q9l!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png 424w, https://substackcdn.com/image/fetch/$s_!1Q9l!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png 848w, https://substackcdn.com/image/fetch/$s_!1Q9l!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.png 1272w, https://substackcdn.com/image/fetch/$s_!1Q9l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd91589a9-0bfb-40b0-be7e-0d6936e68236_3325x995.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>We could do this ourselves manually (i.e. tag one product as related to another), but imagine this overhead at <a href="http://kith.com">Kith</a>-scale! So, instead, we take this query vector (remember, point in space), and find other items (i.e. other points in space) that are <em>approximately </em>the <em>closest </em>(i.e. nearest) to the our Niobiums. Think of ANN as <em>a</em> (alternative methods exist) series of steps that helps us make this &#8220;distance&#8221; calculation.</p><p>Next. What&#8217;s an inverted BM25 index? This is a technique that I wasn&#8217;t familiar with, but again, it sounds more intimidating than it actually is. It&#8217;s considered &#8220;inverted&#8221; as it flips the usual function of an index. Instead of storing &#8220;documents&#8221; (think ~files) &amp; their contents (i.e. data) it stores &#8220;terms&#8221; (e.g. text like &#8220;rubberized&#8221; or &#8220;toecap&#8221;) &amp; a list of &#8220;document IDs&#8221; that contain said term. Par example, let&#8217;s say we have three documents in our Kith database:</p><pre><code>document 1: "Rubberized heel blue" 
document 2: "Toecap chrome finish"
document 3: "Rubberized compressed toecap with t99 cut"</code></pre><p>Our inverted index would look like:</p><pre><code><code>"rubberized": [1, 3] &lt;--- this array is known as a "posting list"
"toecap"    : [2, 3]
"heel"      : [1]
... u get my drift</code></code></pre><p>The &#8220;BM25&#8221; (or Best Matching 25) part is a &#8220;scoring function&#8221; widely used by search engines to rank documents by relevance to a query. This function takes into account variables like: 1) term frequency, 2) document length, 3) how common/rare terms are, etc etc. It should hopefully be clear which document above would be considered most relevant to a query like &#8220;Rubberized toecap&#8221;. Math buffs, if u want the BM25 function here it is: </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;Score(D, Q) = &#931; [IDF(term) * ((TF(term, D) * (k1 + 1)) / (TF(term, D) + k1 * (1 - b + b * (|D| / avgDocLength))))]\n&quot;,&quot;id&quot;:&quot;XCNLWLPZUJ&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>Oh man. This optimisation work by tpuf only gets better (see below). I&#8217;m starting to believe that if an infra company <em>can&#8217;t </em>write architecture docs that include &#8220;optimised for <em>X</em>&#8221; &gt;= 5 times they may not have &#8220;it&#8221;. Gotta lean into your thing vs. someone else&#8217;s.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JTFP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JTFP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 424w, https://substackcdn.com/image/fetch/$s_!JTFP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 848w, https://substackcdn.com/image/fetch/$s_!JTFP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 1272w, https://substackcdn.com/image/fetch/$s_!JTFP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JTFP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png" width="802" height="108" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:108,&quot;width&quot;:802,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32333,&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_!JTFP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 424w, https://substackcdn.com/image/fetch/$s_!JTFP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 848w, https://substackcdn.com/image/fetch/$s_!JTFP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 1272w, https://substackcdn.com/image/fetch/$s_!JTFP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa55e6216-faa4-46f3-a62d-5fd5e19f6cbf_802x108.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ngl, I hadn&#8217;t heard of SPANN (see <a href="https://arxiv.org/pdf/2111.08566">here</a>) or centroids either. To grok SPANN we need to understand centroids, so let&#8217;s start there. Centroids are <em>essentially &#8220;</em>representative&#8221; vectors, meaning that they themselves <em>aren&#8217;t</em> <em>real</em> datapoints in vector space. Instead, they&#8217;re at the centre (i.e. the mean) of a group of other real points in space. I&#8217;m sure that makes almost no sense&#8230; so I&#8217;ll break it down via an example: </p><p>Let&#8217;s go back to our Kith example (hope you all enjoyed <a href="https://open.spotify.com/episode/4CbbQQT5wSsJkTP38xb1sA">this pod</a>). When building our product recommendation engine, we might have 1 million images (i.e. vectors) in our shoe dataset. That&#8217;s a lot of data. So, we could use a clustering algorithm like <a href="https://www.analyticsvidhya.com/blog/2019/08/comprehensive-guide-k-means-clustering/#:~:text=K%2Dmeans%20clustering%20is%20a%20popular%20method%20for%20grouping%20data%20by%20assigning%20observations%20to%20clusters%20based%20on%20proximity%20to%20the%20cluster%E2%80%99s%20center.">k-means</a> to &#8220;cluster&#8221; (i.e group) these 1 million vectors into 1 thousand clusters to &#8220;shrink&#8221; our &#8220;search space&#8221; a little. We then use centroids to essentially <em>identify </em>(i.e. give it its own point in vector space)<em> </em>each cluster. Smart. </p><p>Ok, so, what is <a href="https://arxiv.org/abs/2111.08566">SPANN</a>? Or.. wait for it.. &#8220;Simple yet efficient Partioning-based Approximate Nearest Neighbour&#8221; (&#128565;&#8205;&#128171;) search. Wow, nothing &#8220;simple&#8221; about that. </p><p>Luckily for us, because all of the work we&#8217;ve done in this primer already, <em>it is</em> in fact<em> </em>simple to grok. Basically,<em> </em>the core idea behind SPANN is that it stores centroids in memory (think our NVMe SSD cache) and the underlying vectors that map to these centroids (weirdly, also called &#8220;posting lists&#8221; despite not being an inverted index) on disk storage (i.e. our vanilla object storage). Simple as that. Naturally, this work leads to <em>another</em> performance bump.   </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Will take payment in the form of <a href="http://niobium c_3">Niobium C_3s</a> or otherwise, subscribe?</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>What should we build then? Well, I&#8217;ve kept the below <a href="http://mack.work/advice_aggregated">advice aggregated</a> blog post up-to-date for some time. So, what if instead of visiting it to look for <a href="http://csinvesting.org/wp-content/uploads/2014/05/Worldly-Wisdom-by-Munger.pdf">worldly wisdom</a>, I could just.. query it? (p.s. this page <a href="https://github.com/alexmackenzie-wx/blog">lives on GitHub</a> so add to it via a pull request if ya 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_!W8zy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W8zy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png 424w, https://substackcdn.com/image/fetch/$s_!W8zy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png 848w, https://substackcdn.com/image/fetch/$s_!W8zy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png 1272w, https://substackcdn.com/image/fetch/$s_!W8zy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W8zy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png" width="776" height="1324" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b857785-0137-4703-8946-acab901b02e0_776x1324.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1324,&quot;width&quot;:776,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:245347,&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_!W8zy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png 424w, https://substackcdn.com/image/fetch/$s_!W8zy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png 848w, https://substackcdn.com/image/fetch/$s_!W8zy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.png 1272w, https://substackcdn.com/image/fetch/$s_!W8zy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b857785-0137-4703-8946-acab901b02e0_776x1324.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><em>Very doable</em> with tpuf. I&#8217;ll show you how, but let&#8217;s see it in action first. What results do I get back for the query <a href="https://www.theloganbartlettshow.com/archive/ep-115-josh-wolfe-co-founder-lux-capital-on-uncovering-hidden-opportunities">&#8220;chips on shoulders..&#8221;</a>? So cool.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hBIZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hBIZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png 424w, https://substackcdn.com/image/fetch/$s_!hBIZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png 848w, https://substackcdn.com/image/fetch/$s_!hBIZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png 1272w, https://substackcdn.com/image/fetch/$s_!hBIZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hBIZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png" width="1247" height="926" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3f27aa42-c814-4560-8274-828b05660908_1247x926.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:926,&quot;width&quot;:1247,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:220386,&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_!hBIZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png 424w, https://substackcdn.com/image/fetch/$s_!hBIZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png 848w, https://substackcdn.com/image/fetch/$s_!hBIZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.png 1272w, https://substackcdn.com/image/fetch/$s_!hBIZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f27aa42-c814-4560-8274-828b05660908_1247x926.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>Let&#8217;s see this reflected in turbopuffer&#8217;s dashboard too, and then I promise we&#8217;ll dig into the code. 55 documents (remember, vectors) in there, nice. Looks like tpuf&#8217;ll be passing my own &#8220;toothbrush test&#8221; (see result 10; please laugh at my joke) at this rate. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k1r1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k1r1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png 424w, https://substackcdn.com/image/fetch/$s_!k1r1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png 848w, https://substackcdn.com/image/fetch/$s_!k1r1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png 1272w, https://substackcdn.com/image/fetch/$s_!k1r1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k1r1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png" width="1237" height="1165" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1165,&quot;width&quot;:1237,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81158,&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_!k1r1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png 424w, https://substackcdn.com/image/fetch/$s_!k1r1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png 848w, https://substackcdn.com/image/fetch/$s_!k1r1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.png 1272w, https://substackcdn.com/image/fetch/$s_!k1r1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F761b20fd-8653-4975-892d-32852ea936bf_1237x1165.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>Ok, now for the code. I feel compelled to add that I don&#8217;t think this is in any way a &#8220;difficult&#8221; application to build. I thought about doing something more challenging with <a href="https://www.kaggle.com/datasets/hudsonstuck/stockx-data-contest">StockX&#8217;s Sneaker Data Contest dataset</a>. Maybe over the holidays. Anyway:</p><pre><code>import os
from dotenv import load_dotenv
import turbopuffer as tpuf
from openai import OpenAI

# Load environment variables from .env file
load_dotenv()
turbopuffer_key = os.getenv("TURBOPUFFER_API_KEY")
openai_key = os.getenv("OPENAI_API_KEY")

tpuf.api_key = turbopuffer_key
client = OpenAI(api_key=openai_key)

# Create namespace
<strong>ns = tpuf.Namespace("advice-aggregated-search2")</strong>

# Function to get embeddings from OpenAI with error handling
<strong>def get_embedding(text):
    try:
        response = client.embeddings.create(
            model="text-embedding-ada-002",
            input=text
        )
        return response.data[0].embedding</strong></code></pre><p>Request to Substack &#8212; make prettier code blocks? Would some colour hurt anyone? Jeez. Anyway, as you can see I&#8217;ve bolded what matters in this section of my code. We <em>1)</em> create a &#8220;namespace&#8221; (a collection of data) in turbopuffer &amp; <em>2)</em> create a function that will turn any text we supply (i.e. our advice aggregated list) into word embeddings.  </p><p>Next, we create an array of &#8220;strings&#8221; (i.e. text) that contains our list of advice. This is the text that will be the input into our &#8220;get_embedding&#8221; function above. We then run (or &#8220;call&#8221;) our `get_embedding( )` function to actually turn this text into vectors. Easy. </p><pre><code>advice_items = [
    '"People that scare me" - Graham Duncan on hiring Analysts that are capable of being better than you.',
    '"Look for infinite problem spaces" - Will Gaybrick on market selection.',
    '"Patience is arbitrage" - Mike Maples on the importance of playing long-term games.',
    '"In order to make delicious food, you must eat delicious food." - Karri Saarinen on cultivating taste (via Jiro Dreams of Sushi).',
    '"Moral authority" - Peter Fenton on a founders ability/right to create change in an industry.',
    '"Focus on both music making and conducting" - Josh Kushner on how to refine your investment picking whilst management responsibilities scale.',
    '"Unique and compelling value proposition" - Pat Grady on gross margins &amp; operating margins.',
    '"Suck the oxygen out of the air" - Pat Grady on winning founder mind share. (about Sarah Guo!)',
    '"Do good deals" - Anon on becoming a great investor. "Obvious" - but very easy to climb the wrong hill',
    '"Look at the steepness of the slope" - Geoff Lewis on assessing talent.',

...... etc

# Create vectors for each piece of advice
<strong>for idx, advice in enumerate(advice_items):
     try:
         embedding = get_embedding(advice)
         if embedding:  # Only proceed if we got a valid embedding
             ns.upsert(
                 ids=[f"advice_{idx}"],
                 vectors=[embedding]
             )
             print(f"Processed item {idx + 1}/{len(advice_items)}")  #</strong> Progress indicator
             time.sleep(0.5)  # Add small delay to avoid rate limits

print("Vectorization complete!")</code></pre><p>Ok, final part and then we&#8217;re all wrapped up. Next, we turn our desired search query (remember, &#8220;chips on shoulders&#8221;) into a vector too. This will enable us to query our namespace (using the `ns.query( )` function below) by searching for those vectors that are <em>approximately</em> &#8220;close&#8221; to the query in vector space. We then just print the results.   </p><pre><code>search_query = "chips on shoulders"
query_embedding = get_embedding(search_query)

# Query the namespace for similar vectors
results = ns.query(
    vector=query_embedding,  # The embedding of your search query
    top_k=10,  # Number of results you want to return
    distance_metric="cosine_distance",  # Assuming cosine distance is appropriate
    include_attributes=[],  # Adjust based on what attributes you need
    include_vectors=False
)

# Print the results
for idx, result in enumerate(results):
    # Debugging: Print the result object to understand its structure
    print(f"Result {idx + 1}: {result}")

    # Assuming result has attributes like 'id' and 'dist', access them directly
    item_id = result.id  # Accessing as an attribute
    score = result.dist  # Use 'dist' instead of 'score'

    # Get the original advice text using the ID (it will be something like 'advice_27')
    original_idx = int(item_id.split('_')[1])
    print(f"\nResult {idx + 1}:")
    print(f"Text: {advice_items[original_idx]}")
    print(f"Similarity Score: {score}")
</code></pre><p>&amp; that, dear readers, is the end of our primer on turbopuffer. I hope you had as much fun reading as I did writing this one. A special thanks to the tpuf team again. Oh &amp;, subscribe below, and, as always, feel free to say hi at alex@tapestry.vc </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">My next primer will (likely) be on <a href="https://skiplabs.io/">Skip</a> or <a href="https://northflank.com/">Northflank</a>. Subscribe to keep updated.</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>]]></content:encoded></item><item><title><![CDATA[Browserbase]]></title><description><![CDATA[APIs for The Internet]]></description><link>https://whynowtech.substack.com/p/browserbase</link><guid isPermaLink="false">https://whynowtech.substack.com/p/browserbase</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Mon, 02 Dec 2024 16:02:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!vp-8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg" 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_!vp-8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vp-8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg 424w, https://substackcdn.com/image/fetch/$s_!vp-8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg 848w, https://substackcdn.com/image/fetch/$s_!vp-8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!vp-8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vp-8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg" width="720" height="405.13119533527697" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:386,&quot;width&quot;:686,&quot;resizeWidth&quot;:720,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;LOUIE - FULL ALBUM VISUALIZER&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="LOUIE - FULL ALBUM VISUALIZER" title="LOUIE - FULL ALBUM VISUALIZER" srcset="https://substackcdn.com/image/fetch/$s_!vp-8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg 424w, https://substackcdn.com/image/fetch/$s_!vp-8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg 848w, https://substackcdn.com/image/fetch/$s_!vp-8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!vp-8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff55a7dbc-a225-4ead-8f79-1f51c2722bb0_686x386.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"><a href="https://www.youtube.com/watch?v=M1v5fvBP5TM&amp;t=1496s">LOUIE</a></figcaption></figure></div><p><em>For new folk here, hi, I&#8217;m <a href="https://x.com/alex__mackenzie">Alex Mackenzie</a>, a partner at <a href="https://www.tapestry.vc/">Tapestry</a>. I&#8217;d love to hear from any of you reading along: alex@tapestry.vc</em></p><div><hr></div><p>Recently I listened to <a href="https://www.youtube.com/watch?v=h0-QEJ0vd78">Kenny Beats&#8217;</a> (<em>&#8220;Whoa, Kenny!&#8221;</em>) <a href="https://www.youtube.com/watch?v=nTtp8OD3Gq8">interview</a> on Tetragrammaton. I&#8217;d recommend tuning in for many reasons, but it got me thinking about the &#8216;<a href="https://x.com/blakeir#:~:text=hanging%20out%20on%20the%20edges%20of%20the%20internet">edges of the internet</a>&#8217;. Shortly after, I thought about queuing for Glastonbury tickets, which got me thinking about.. browser automation.. and thus, this primer was born.</p><p>By &#8216;edges of the internet&#8217;, I mean places that you personally frequent that feel a little proprietary..? They&#8217;re earned. For me, that could be <a href="https://www.factorio.com/blog/">Factorio&#8217;s blog</a>, PC&#8217;s <a href="https://patrickcollison.com/fast">fast list</a>, or, perhaps, Polymarket&#8217;s Chess <a href="https://polymarket.com/sports/chess/props">prop bets</a>. Who ya <a href="https://polymarket.com/event/world-chess-championship-2024-winner?tid=1731853095620">got</a>?</p><p>The problem with many of these &#8216;edges&#8217; is that they&#8217;re often <em>webpages</em>, not <em>webapps.</em> You have to remember to visit &#8216;em, write &#8216;em down <a href="https://mack.work/reads_and_thoughts">somewhere</a>, parse them for the content you enjoy, etc. Or, even when they are webapps, you&#8217;re beholden to an <a href="https://developer.x.com/en/docs/api-reference-index">API reference</a>. What if you want access to data that an API doesn&#8217;t provide?</p><p>This is where scraping and browser automation (both of which we&#8217;ll dig into in detail) come in. Theoretically, with these two techniques, you can turn any web-page into a web-api. We&#8217;ll learn how later, by having a bit of fun and building our own <a href="https://news.ycombinator.com/">HN</a> tool.</p><p>It&#8217;s likely at this point that you&#8217;re thinking &#8216;isn&#8217;t scraping and browser automation old news?&#8217;. In short &#8212; yes. However, have you ever tried to build a durable web scraper? If not, just know that it&#8217;s not exactly trivial. Plus, Selenium <a href="https://x.com/wolfejosh/status/1517882017622417409">kinda sucks</a>. </p><p>There&#8217;s also a <a href="https://github.com/browserbase/stagehand">genuine opportunity</a> to put LLMs to work here which we&#8217;ll dig into. Personally, I&#8217;m very excited about never having to write a line of .*(?!regex).* again. <em>Whoa, Kenny!</em> indeed.</p><p>Accordingly, I was happy to see <a href="https://www.linkedin.com/in/paulkleiniv">Paul</a> and the team at <a href="https://www.browserbase.com/">Browserbase</a> taking things up a notch. Fwiw, I&#8217;ve been using Browserbase for weeks now and I&#8217;m a happy (paying!) customer. So, let&#8217;s see what all the fuss is about. </p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for more technical primers! <a href="https://turbopuffer.com/">turbopuffer</a> is next.</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>Ok, so, as discussed, we&#8217;ll learn about the evolution of scraping, browser automation, and Browserbase itself by building a Hacker News tool. It will:</p><ol><li><p>Run every morning at 9am via a cron job (check out <a href="https://northflank.com/">Northflank</a>).</p></li><li><p>Pull the top 30 posts (i.e. the &#8216;front page&#8217;) on the HN site (<a href="https://www.browserbase.com/">Browserbase</a>).</p></li><li><p>Click into the hyperlink of each post (<a href="https://www.browserbase.com/">Browserbase</a>).</p></li><li><p>Summarise each post (<a href="https://chatgpt.com/">ChatGPT API</a>).</p></li><li><p>Send an email about these posts (<a href="https://resend.com/">Resend</a>).  </p></li></ol><p><em>Note 1: I&#8217;ll include the code I use so that folk can follow along, but you don&#8217;t need to fully grok the code itself. If you get stuck, or want more context, try throwing the code in your favourite LLM and asking some Qs.</em></p><p><em>Note 2: If you&#8217;re following along, I <strong>recommend using <a href="https://flox.dev/">Flox</a></strong> to install the dependencies we use.</em> <em>It&#8217;ll keep your system clean &amp; conflict free.</em></p><div><hr></div><p><strong>1. Scraping 101</strong></p><p>Whilst I was, correctly, <em>far</em> too occupied battling the <a href="https://en.wikipedia.org/wiki/Pok%C3%A9mon_(video_game_series)#:~:text=November%2018%2C%202022.-,1996%E2%80%931998%3A%20First%20generation,-Further%20information%3A">Elite Four</a> (iykyk) in the 1990s to care, I&#8217;m told that web scraping was pretty straightforward &#8220;back then&#8221;. Websites essentially looked like this: <a href="http://thegestalt.org/simon/ps2rant.html">http://thegestalt.org/simon/ps2rant.html</a>. </p><p>I.e. they were often walls of text with no real interactivity or client-side rendering. And yes, this post is the <a href="http://thegestalt.org/simon/">co-founder of Fastly</a> complaining about the PS2. I did tell you, I spend far too much time on the internet.  </p><p>Let&#8217;s see how we can scrape websites that look like this. Let&#8217;s first use <a href="https://curl.se/">cURL</a> (fun fact: prev named <a href="https://en.wikipedia.org/wiki/CURL#:~:text=It%20was%20originally%20named%20httpget%20and%20then%20became%20urlget">httpget and urlget</a>) to retrieve the webpage:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2pIp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2pIp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 424w, https://substackcdn.com/image/fetch/$s_!2pIp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 848w, https://substackcdn.com/image/fetch/$s_!2pIp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 1272w, https://substackcdn.com/image/fetch/$s_!2pIp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2pIp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png" width="1000" height="532" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:532,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:108031,&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_!2pIp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 424w, https://substackcdn.com/image/fetch/$s_!2pIp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 848w, https://substackcdn.com/image/fetch/$s_!2pIp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 1272w, https://substackcdn.com/image/fetch/$s_!2pIp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f4b89d6-7981-470c-a799-04e1d25f3cff_1000x532.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is fine, but cURL doesn&#8217;t include any built-in text processing tools, so we have to use command line utilities like <a href="https://en.wikipedia.org/wiki/Grep#:~:text=grep%20is%20a,%5B5%5D">&#8216;grep&#8217;</a>, <a href="https://en.wikipedia.org/wiki/AWK#:~:text=AWK%20(/%C9%94%CB%90k/%5B4%5D)%20is%20a%20domain%2Dspecific%20language%20designed%20for%20text%20processing%20and%20typically%20used%20as%20a%20data%20extraction%20and%20reporting%20tool.%20Like%20sed%20and%20grep%2C%20it%20is%20a%20filter%2C%5B4%5D%20and%20it%20is%20a%20standard%20feature%20of%20most%20Unix%2Dlike%20operating%20systems.">&#8216;awk&#8217;</a> or <a href="https://en.wikipedia.org/wiki/Sed#:~:text=sed%20(%22stream%20editor,and%20Perl.">&#8216;sed&#8217;</a> to process this data further. Par example, if we want to extract the URL&#8217;s included in Simon&#8217;s post we&#8217;d use &#8216;awk&#8217;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ddYp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ddYp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png 424w, https://substackcdn.com/image/fetch/$s_!ddYp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png 848w, https://substackcdn.com/image/fetch/$s_!ddYp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png 1272w, https://substackcdn.com/image/fetch/$s_!ddYp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ddYp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png" width="1225" height="545" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:545,&quot;width&quot;:1225,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59845,&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_!ddYp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png 424w, https://substackcdn.com/image/fetch/$s_!ddYp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png 848w, https://substackcdn.com/image/fetch/$s_!ddYp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.png 1272w, https://substackcdn.com/image/fetch/$s_!ddYp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ebede6d-42e2-4f4a-817b-6b706579e5ba_1225x545.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>&#8216;awk&#8217;(ward) being the operative word here, this command is hard for me to interpret, and I wrote it yesterday.. things can get unwieldy, fast, if we want to do more complex text processing:</p><pre><code>curl -s http://thegestalt.org/simon/ps2rant.html | \
sed -n 's/.*&gt;\(.*\)&lt;.*/\1/p' | \
tr '[:upper:]' '[:lower:]' | \
tr -c '[:alnum:]' '[\n*]' | \
awk 'NF' | \
sort | \
uniq -c | \
sort -nr | \
head -n 10 </code></pre><p>I&#8217;d more readily <a href="https://en.wikipedia.org/wiki/Cuneiform#:~:text=4th%20millennium%20BC.-,A%20proto%2Dcuneiform%20tablet%2C%20Jemdet%20Nasr%20period%2C%20c.%E2%80%893100%E2%80%932900%20BC.,-A%20proto%2Dcuneiform">read Cuneiform</a>! Let&#8217;s keep in mind however, that Simon&#8217;s webpage is very basic by modern standards (although I do like the recent vanilla html &#8216;<a href="https://planetscale.com/">comeback</a>&#8217;). Brace yourselves, as you see what happens when we &#8216;cURL&#8217; Hacker News:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-8BR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-8BR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png 424w, https://substackcdn.com/image/fetch/$s_!-8BR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png 848w, https://substackcdn.com/image/fetch/$s_!-8BR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png 1272w, https://substackcdn.com/image/fetch/$s_!-8BR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-8BR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png" width="1076" height="811" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:811,&quot;width&quot;:1076,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:269654,&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_!-8BR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png 424w, https://substackcdn.com/image/fetch/$s_!-8BR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png 848w, https://substackcdn.com/image/fetch/$s_!-8BR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.png 1272w, https://substackcdn.com/image/fetch/$s_!-8BR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98384e0a-2e5a-44c7-8eb3-3e036d240183_1076x811.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><em>Eugh!</em> Modern webpages have <em>a lot </em>more going on. Also, it&#8217;s not like Hacker News is going to win a <a href="https://www.webbyawards.com/">Webby</a> anytime soon (sorry, PG); it&#8217;s still pretty basic. &#8216;<a href="https://pypi.org/project/beautifulsoup4/">BeautifulSoup</a>&#8217; and &#8216;<a href="https://pypi.org/project/requests/">Requests</a>&#8217; came along in 2004 and 2011 respectively to make parsing modern webpages like this a little easier.</p><p>Let&#8217;s use Requests (for making http requests) and BeautifulSoup (for html parsing) to visit the Hacker News page and extract every title on the front page as well as their corresponding hyperlinks. I&#8217;ll bold some functionality that I think is worth noting but, don&#8217;t fret if this code is confusing. I&#8217;ll elaborate on what&#8217;s important.  </p><pre><code>
file name: hacker_news_bs4.py
------------------------------------------------------------------------

import requests
from bs4 import BeautifulSoup
from typing import List, Tuple

def scrape_hacker_news() -&gt; List[Tuple[str, str]]:
    # Base URL for Hacker News
    url = "https://news.ycombinator.com/"
    
    # Send GET request
    <strong>response</strong> = requests.get(url)
        
    # Parse HTML content
    soup = BeautifulSoup(<strong>response.text</strong>, <strong>'html.parser'</strong>)
    
    <strong># Find all story titles (they are in 'titleline' class)</strong>
    stories = []
    
    # Find all story rows (they have class 'athing')
    for story in <strong>soup.find_all('tr', class_='athing')</strong>:
        # Find the title span
        titleline = <strong>story.find('span', class_='titleline')</strong>
        if titleline:
            # Get the first link in the titleline
            link_tag = titleline.find('a')
            if link_tag:
                title = <strong>link_tag.get_text()</strong>
                # Get href attribute, if it's a relative URL, prepend the base URL
                link = link_tag.get('href')
                if link.startswith('item?'):
                    link = url + link
                    
                stories.append((title, link))
    
    return stories

def main():
    try:
        stories = scrape_hacker_news()
        
        # Print the results
        print(f"Found {len(stories)} stories:\n")
        for i, (title, link) in enumerate(stories, 1):
            print(f"{i}. {title}")
            print(f"   Link: {link}\n")
            
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    main()</code></pre><p>If this is your first time looking at BeautifulSoup it may look a little overwhelming; the most important item to note is that the library gives you tools (or functions) like &#8216;.find_all( )&#8217; or &#8216;.get_text( )&#8217; that can search for html like <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#:~:text=The%20%3Ca%3E,will%20activate%20it.">anchor tags</a> or specific <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors#:~:text=The%20CSS%20class%20selector%20matches%20elements%20based%20on%20the%20contents%20of%20their%20class%20attribute.">CSS class</a> names like &#8216;athing&#8217;. These libraries ultimately make parsing webpages a hell&#8217;uva lot easier.</p><p>Let&#8217;s see what our HN code returns when we run the above script:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hjAx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hjAx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png 424w, https://substackcdn.com/image/fetch/$s_!hjAx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png 848w, https://substackcdn.com/image/fetch/$s_!hjAx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png 1272w, https://substackcdn.com/image/fetch/$s_!hjAx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hjAx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png" width="1456" height="1070" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1070,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:427573,&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_!hjAx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png 424w, https://substackcdn.com/image/fetch/$s_!hjAx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png 848w, https://substackcdn.com/image/fetch/$s_!hjAx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.png 1272w, https://substackcdn.com/image/fetch/$s_!hjAx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7313b860-324b-4b15-a850-1dbb95d6d062_2088x1534.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>Nice, we&#8217;ve made progress here (<a href="https://github.com/p8952/bocker">Bocker</a> looks cool). But remember, we also want to &#8216;click&#8217; into the hyperlink of each post. We can<em> technically</em> do this with BeautifulSoup and Requests, but we&#8217;ll likely run into some difficulties which I&#8217;ll outline in the next section below.<br></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">&#8216;Click&#8217; that subscribe button the &#8216;analog&#8217; way. Remember, <a href="https://turbopuffer.com/">turbopuffer</a> is next.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><strong>2. Along Came Browser Automation</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_!Ceru!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ceru!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png 424w, https://substackcdn.com/image/fetch/$s_!Ceru!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png 848w, https://substackcdn.com/image/fetch/$s_!Ceru!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png 1272w, https://substackcdn.com/image/fetch/$s_!Ceru!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ceru!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png" width="1400" height="1094" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1094,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Henrik Larsson | Celtic FC Profile&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="Henrik Larsson | Celtic FC Profile" title="Henrik Larsson | Celtic FC Profile" srcset="https://substackcdn.com/image/fetch/$s_!Ceru!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png 424w, https://substackcdn.com/image/fetch/$s_!Ceru!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png 848w, https://substackcdn.com/image/fetch/$s_!Ceru!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.png 1272w, https://substackcdn.com/image/fetch/$s_!Ceru!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ba22811-2b00-4cae-8e11-7ba5be204b27_1400x1094.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">again, iykyk</figcaption></figure></div><p>With the advent of JavaScript (which I wrote about in my <a href="https://whynowtech.substack.com/p/deno">primer</a> on Deno), came the &#8216;dynamic&#8217; webpage. JavaScript enables websites to render, and/or change, &#8216;client-side&#8217; (i.e. on a user&#8217;s device) vs. on a server.    </p><p><a href="https://onefootball.com/es/noticias/celtic-vs-rangers-everything-we-know-about-the-old-firm-rivalry-37998560">Celtic and Rangers</a> fans are more likely to &#8216;get on&#8217; than those debating the pros/cons of client-side rendering, so let&#8217;s not get into the weeds here. Instead, let&#8217;s understand why client-side rendering spoiled our (Beautiful)Soup via an example. </p><p>Recently, I tried to scrape the Public Comps (non-gated) <a href="https://www.publiccomps.com/tickers?items=High+Growth+SaaS">dashboard</a> using Requests and BeautifulSoup. When you do so, you receive a bunch of HTML (mainly just <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Positions#:~:text=For%20all%20elements,to%20the%20bottom.">SVG coordinates</a>), but no company data. Visit the site, and have a guess why this may be? </p><p>Go on. <a href="https://www.publiccomps.com/tickers?items=High+Growth+SaaS">Visit it</a>. </p><p>This data is rendered client-side! How this webpage likely works is that when it&#8217;s first loaded, a basic HTML skeleton is rendered. <em>Then</em>, the webpage itself will make an API call (or &#8216;fetch&#8217;) the underlying data that populates the corresponding charts. The issue with BeautifulSoup &amp; Requests is that it: </p><ol><li><p>Only sees a webpage&#8217;s initial HTML.</p></li><li><p>Can't execute JavaScript (e.g. clicking a button) to render dynamic content.</p></li><li><p>~Can't make the subsequent API calls that load the actual data.</p></li><li><p>Can&#8217;t authenticate (i.e. log-in) via modern auth to a given website or webapp.  </p></li></ol><p>I&#8217;m sure many of the links returned by our HN scraper will act similarly to Public Comps, and so, we need an alternative approach. Something more.. robust. <em>Along Came Browser Automation</em>. </p><p>Let&#8217;s take a step back for a second. When we&#8217;re using the Google Chrome &#8216;app&#8217; ourselves, we don&#8217;t run into any of the above issues, right? Cool animations run, buttons can be clicked, images are downloadable, et cetera.      </p><p>We &#8216;control&#8217; this Google Chrome app with our mouse and keyboard and all works swimmingly. So, what if we could control this same app, but with code? This was <a href="https://www.linkedin.com/in/jrhuggins/">Jason Huggins&#8217;</a> core idea with <a href="https://www.selenium.dev/">Selenium</a> back in 2004. </p><p>Let&#8217;s build our HN tool using Selenium this time. Remember, I think &#8216;Selenium <a href="https://x.com/wolfejosh/status/1517882017622417409">kinda sucks</a>&#8217;. I won&#8217;t share my Selenium code (it will overcomplicate things), but I will share snippets that&#8217;ll highlight its flaws. But first, proof that Selenium can get the job done:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Dqpa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Dqpa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png 424w, https://substackcdn.com/image/fetch/$s_!Dqpa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png 848w, https://substackcdn.com/image/fetch/$s_!Dqpa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png 1272w, https://substackcdn.com/image/fetch/$s_!Dqpa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Dqpa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png" width="831" height="906" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:906,&quot;width&quot;:831,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:210651,&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_!Dqpa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png 424w, https://substackcdn.com/image/fetch/$s_!Dqpa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png 848w, https://substackcdn.com/image/fetch/$s_!Dqpa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.png 1272w, https://substackcdn.com/image/fetch/$s_!Dqpa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F674a8b68-d679-4db7-8e8a-bc3d73ac477e_831x906.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>Ok, so why the Selenium <a href="https://dictionary.cambridge.org/dictionary/french-english/boeuf">boeuf</a>? Well, firstly, look at the extensive set of dependencies and complex config it requires:</p><pre><code>
# There's a bunch of 'scaffolding' that needs to be imported

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import time
import json

# Configures the Chrome web driver

def setup_driver():
    options = Options()
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    options.add_argument('--window-size=1920,1080')
    
    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=options) </code></pre><p><em>Eugh! Again!</em> Cursor (see my <a href="https://whynowtech.substack.com/p/cursor-beyond-the-hype">primer here</a> if interested) has made my life <em>so much </em>easier now, but I used to spend <em>hours </em>getting this set-up right. This used to take all of the fun out of building scrapers. I guess this has changed now..</p><p>..what hasn&#8217;t changed, however, is how &#8216;brittle&#8217; Selenium&#8217;s CSS selectors are. You might recall that our HN scraper looks for the CSS class called &#8220;athing&#8221;; this is fine, until the developers of HN decide to change their class naming conventions. If this class changes, and is now called &#8220;athing2&#8221;, our entire scraper breaks. <em>No bueno</em>.</p><p>There&#8217;s a plurality (minimal <a href="https://stackoverflow.com/questions/58872451/how-can-i-bypass-the-google-captcha-with-selenium-and-python#:~:text=To%20start%20with%20using%20Selenium%27s%20Python%20clients%2C%20you%20should%20avoid%20solving/bypass%20Google%20CAPTCHA.">CAPTCHA support</a>, <a href="https://github.com/SeleniumHQ/selenium/issues/13872">high resource usage</a>, <a href="https://stackoverflow.com/questions/60872839/leaking-memory-when-using-selenium-webdriver-in-a-for-loop">memory leaks</a>) of other small issues that add up to make the maintenance of a Selenium script a bit of a nightmare. <em>Hopefully</em>, you&#8217;ve built a sense for why we might want something a little different? Some names such as <a href="https://playwright.dev/">Playwright</a>, <a href="https://pptr.dev/">Puppeteer</a> and, now, <a href="https://www.browserbase.com/">Browserbase</a>, came along to help us all out. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">1 sub = no more selenium code</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><strong>3. Browserbase - APIs For The Internet</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_!5rhz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5rhz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!5rhz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!5rhz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!5rhz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5rhz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png" width="1200" height="630" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:630,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Browserbase's Pledge to Open Source - Browserbase - Headless Web Browser API&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="Browserbase's Pledge to Open Source - Browserbase - Headless Web Browser API" title="Browserbase's Pledge to Open Source - Browserbase - Headless Web Browser API" srcset="https://substackcdn.com/image/fetch/$s_!5rhz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 424w, https://substackcdn.com/image/fetch/$s_!5rhz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 848w, https://substackcdn.com/image/fetch/$s_!5rhz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 1272w, https://substackcdn.com/image/fetch/$s_!5rhz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe3230c0-88e2-4a72-a5a9-4cbd265ed12f_1200x630.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Ok. So, <em>what is</em> Browserbase? Let&#8217;s go with <a href="https://docs.browserbase.com/introduction#:~:text=Browserbase%20offers%20a%20reliable%2C%20high%20performance%20serverless%20developer%20platform%20to%20run%2C%20manage%2C%20and%20monitor%20headless%20browsers%20at%20scale.%20Leverage%20our%20infrastructure%20to%20power%20your%20web%20automation%20and%20AI%20agents.">their definition</a> which we&#8217;ll then break down in our own way: </p><p>&#8216;Browserbase offers a <strong>reliable</strong>, <strong>high performance</strong> serverless <strong>developer platform</strong> to <strong>run</strong>, <strong>manage</strong>, and <strong>monitor</strong> headless browsers at scale. Leverage our <strong>infrastructure</strong> to power your web automation and AI agents.&#8217; </p><p>Let&#8217;s start with what is likely Browserbase&#8217;s most experimental (yet profound) feature, <a href="https://github.com/browserbase/stagehand">Stagehand</a>. I&#8217;ve always liked Josh Wolfe&#8217;s <a href="https://mack.work/advice_aggregated#:~:text=%22Pay%20attention%20to%20directional%20arrows%20of%20progress%22%20%2D%20Josh%20Wolfe.">framing</a> of &#8216;following directional arrows of progress&#8217;; in browser automation&#8217;s case, we&#8217;ve been trending towards selecting html and/or css elements via natural language <em>for years.</em> </p><p>Why? Well, the end goal has always been to get your code to &#8216;<a href="https://github.com/browserbase/stagehand#:~:text=Each%20Stagehand%20function%20takes%20in%20an%20atomic%20instruction%2C%20such%20as%20act(%22click%20the%20login%20button%22)%20or%20extract(%22find%20the%20red%20shoes%22)%2C%20generates%20the%20appropriate%20Playwright%20code%20to%20accomplish%20that%20instruction%2C%20and%20executes%20it.">click the log-in button</a>&#8217;, but until LLMs, we had to use weak proxies such as: &#8216;page.click(".login-button")&#8217; to do so. No longer. How so?</p><p>Well, at a (very) high-level, Stagehand consists of two functions: <a href="https://github.com/browserbase/stagehand#:~:text=act()%20allows%20Stagehand%20to%20interact%20with%20a%20web%20page.%20Provide%20an%20action%20like%20%22search%20for%20%27x%27%22%2C%20or%20%22select%20the%20cheapest%20flight%20presented%22%20(small%20atomic%20goals%20perform%20the%20best).">&#8216;act( )&#8217;</a> and <a href="https://github.com/browserbase/stagehand#:~:text=extract()%20grabs%20structured%20text%20from%20the%20current%20page%20using%20zod.%20Given%20instructions%20and%20schema%2C%20you%20will%20receive%20structured%20data.%20Unlike%20some%20extraction%20libraries%2C%20stagehand%20can%20extract%20any%20information%20on%20a%20page%2C%20not%20just%20the%20main%20article%20contents.">&#8216;extract( )&#8217;</a>.</p><p>&#8216;act( )&#8217; allows Stagehand to interact with a webpage. If we visit <a href="https://www.endclothing.com/us">End Clothing</a>, we could provide the act function with some natural language like &#8216;act(&#8220;search for Palace hats&#8221;)&#8217; or &#8216;act(&#8220;click on the first shoe&#8221;)&#8217; &amp; Stagehand will <em>dynamically generate</em> the underlying Playwright code to get the job done. <em>I cannot stress enough how cool this is.</em>  </p><p>&#8216;extract( )&#8217; does what you&#8217;d likely expect.. it grabs structured text from the webpage. Par example, we could &#8216;extract(&#8220;the price of the first shoe&#8221;)&#8217; or &#8216;extract(&#8220;the navbar&#8221;)&#8217;. Hopefully, you&#8217;re starting to see how leveraging natural language makes our browser automation much more robust, or, <strong>reliable </strong>(see definition above). Let&#8217;s see if these functions enable us to build our HN tool in its final form?:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!osJT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!osJT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 424w, https://substackcdn.com/image/fetch/$s_!osJT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 848w, https://substackcdn.com/image/fetch/$s_!osJT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 1272w, https://substackcdn.com/image/fetch/$s_!osJT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!osJT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png" width="728" height="286.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:469723,&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_!osJT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 424w, https://substackcdn.com/image/fetch/$s_!osJT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 848w, https://substackcdn.com/image/fetch/$s_!osJT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 1272w, https://substackcdn.com/image/fetch/$s_!osJT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff56952c6-0dd7-4bda-981e-881139c716c4_3099x1220.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There ya have it. Our Hacker News Daily Summary email. Nice one Browserbase. </p><p>Browserbase does <em>a lot </em>more on the reliability front though. Remember, most sites don&#8217;t like browser automation, or, &#8216;bots&#8217;, so they&#8217;re constantly trying to thwart our efforts. <em>Boo!</em> To combat bots, websites will try and &#8216;fingerprint&#8217; (i.e. record and recognise) your device by tracking attributes such as your: browser version, IP address, website activity, etc. It&#8217;s really quite smart. </p><p>So, how do we fight back? We won&#8217;t dig into everything Browserbase does, but I think it&#8217;s worth understanding <a href="https://oxylabs.io/blog/what-is-residential-proxy#:~:text=and%20geographic%20location.-,What%20is%20a%20residential%20proxy%3F,-A%20residential%20proxy">&#8216;residential proxies&#8217;</a> as one arrow in our quiver. As noted, one way to spot-a-bot is to track IP addresses. If a given IP address consistently interacts with a site in some predictable manner, at a predictable interval, the site may block its access or throw a CAPTCHA at it. </p><p>So, logically, one way to fight back is to not use our own IP address, but instead, route our request through another server (or, &#8216;proxy&#8217;) to mask our presence. The &#8216;top grade&#8217; of proxy servers is a &#8216;residential proxy&#8217;, which is a legitimate device (think a personal computer or router) that belongs to an actual household. Browserbase enables us to tap into a configurable network of these proxies. Pretty sweet.  </p><div><hr></div><p>Alright, let&#8217;s dig into Browserbase&#8217;s developer platform and then we&#8217;ll wrap up. And before you say it.. I know my product screenshots don&#8217;t exactly look <a href="https://linear.app/#:~:text=Powering%20the%20world%E2%80%99s%20best%20product%20teams">like Linear&#8217;s</a>.. but hey, I guess my writing is ok. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wmoX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wmoX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png 424w, https://substackcdn.com/image/fetch/$s_!wmoX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png 848w, https://substackcdn.com/image/fetch/$s_!wmoX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png 1272w, https://substackcdn.com/image/fetch/$s_!wmoX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wmoX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png" width="1456" height="426" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/86a99040-300b-41a3-aab6-e571be387755_3423x1002.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:426,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:394025,&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_!wmoX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png 424w, https://substackcdn.com/image/fetch/$s_!wmoX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png 848w, https://substackcdn.com/image/fetch/$s_!wmoX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.png 1272w, https://substackcdn.com/image/fetch/$s_!wmoX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86a99040-300b-41a3-aab6-e571be387755_3423x1002.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>So, what you&#8217;re seeing above is where the action is &#8212; Browserbase&#8217;s &#8216;Sessions&#8217; tab. Each time we run a browser automation with Browserbase we get a full play-by-play of what happens. </p><p>For each &#8216;session&#8217; (i.e. each time we run our script) we can see: what pages we visit, the page&#8217;s corresponding &#8216;DOM&#8217; (or <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">&#8216;document object model&#8217;</a>), the network requests (e.g. API calls) a given website makes, etc. This is super helpful for understanding <em>exactly </em>what our scraper is doing, as well as for debugging any reliability or performance issues. Finally, browser automation has a modern developer experience! <em> </em> </p><div><hr></div><p>So.. yeah, I guess we&#8217;re kind of done here. Well, publicly at least; I have so much cool sh*t I want to build behind the scenes for us at <a href="https://www.tapestry.vc/">Tapestry</a>.. but I couldn&#8217;t share that :) I would encourage you all to visit your own &#8216;corner of the internet&#8217; and ask yourself, could I turn this into an API? If so, fire away and let me know what you think of <a href="https://flox.dev/">Flox</a>, <a href="https://northflank.com/">Northflank</a>, and, of course, <a href="https://www.browserbase.com/">Browserbase</a> &#128526;</p><p>Oh and subscribe for my next primer on <a href="https://turbopuffer.com/">Turbopuffer</a>! (&amp; if someone can get me beta access to Turbopuffer, do a brother a solid). Thank you all for reading, I have a tonne of fun writing these.  </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe, tell your friends, etc etc!</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[Cursor - beyond the hype]]></title><description><![CDATA[I&#8217;m only human, and perhaps LLMs are too]]></description><link>https://whynowtech.substack.com/p/cursor-beyond-the-hype</link><guid isPermaLink="false">https://whynowtech.substack.com/p/cursor-beyond-the-hype</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Mon, 16 Sep 2024 16:01:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/734c841c-6269-4d3c-8d05-38687c308ffd_2944x800.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Add to the discussion on Twitter &amp; LinkedIn <a href="https://x.com/alex__mackenzie">here</a> and <a href="https://www.linkedin.com/in/alex-mackenzie-6aa80ab4/">here</a>. Thanks for reading!</em></p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5NFn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5NFn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png 424w, https://substackcdn.com/image/fetch/$s_!5NFn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png 848w, https://substackcdn.com/image/fetch/$s_!5NFn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png 1272w, https://substackcdn.com/image/fetch/$s_!5NFn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5NFn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png" width="1456" height="396" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:396,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Pricing | Cursor - The AI-first Code Editor&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="Pricing | Cursor - The AI-first Code Editor" title="Pricing | Cursor - The AI-first Code Editor" srcset="https://substackcdn.com/image/fetch/$s_!5NFn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png 424w, https://substackcdn.com/image/fetch/$s_!5NFn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png 848w, https://substackcdn.com/image/fetch/$s_!5NFn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.png 1272w, https://substackcdn.com/image/fetch/$s_!5NFn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43b81b32-48fb-4422-b24e-82e8233d18de_2944x800.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>Last Friday a friend and I were sipping one of the <a href="https://gritchiepubs.com/">Lore of the Land&#8217;s</a> finest stouts when he asked: <em>&#8220;why <a href="https://www.cursor.com/">Cursor</a>?&#8221;</em>. </p><p>You see, I shared with him that I&#8217;ve tried the gamut of IDEs and VS Code extensions: <a href="https://www.jetbrains.com/pycharm/">PyCharm</a> to <a href="https://zed.dev/">Zed</a>, <a href="https://codeium.com/">Codium</a> to <a href="https://github.com/features/copilot">Copilot</a>, but that Cursor has been the only one to truly.. &#8220;stick&#8221;. When expounding on my answer, I noticed myself rather haphazardly listing off product features that I enjoy vs. providing him with a crisp response. </p><p>As I&#8217;ve thought more about this moment, I&#8217;ve realised that within this feature list actually lies an explanation I&#8217;m ok with. Many of my most beloved products and brands <a href="https://nothing.tech/">[1]</a><a href="https://teenage.engineering/">[2]</a><a href="https://linear.app/">[3]</a> string together <a href="https://docs.cursor.com/get-started/migrate-from-vscode#why-is-the-activity-bar-in-cursor-horizontal">seemingly inconsequential</a> product decisions that, in aggregate, make them truly different. Par example, I didn&#8217;t expect Nothing&#8217;s <a href="https://ie.nothing.tech/pages/phone-2#GLYPH-INTERFACE">glyph interface</a> to change my life, but it kinda has.</p><p>In Cursor&#8217;s case, these small decisions are derived from the LLM being a first-class citizen as opposed to an afterthought. For example, the fact that Cursor&#8217;s activity bar is <a href="https://docs.cursor.com/get-started/migrate-from-vscode#why-is-the-activity-bar-in-cursor-horizontal">horizontal vs. vertical</a> is trivial, but it likely means that they&#8217;ve found another 100+ ways to create space and context for <a href="https://docs.cursor.com/chat/overview#:~:text=Cursor%20Chat%20lets%20you%20ask%20questions%20or%20solve%20problems%20in%20your%20codebase%20with%20the%20most%20capable%20language%20models%2C%20all%20in%20your%20editor.">Cursor Chat</a>. The collective is far less trivial. </p><p>Herein lies another learning. The word &#8220;native&#8221; (cloud-native, LLM-native, etc) gets thrown around a lot in tech, but it&#8217;s a <a href="https://cloudsmith.com/blog/what-makes-cloudsmith-special-reflections-on-1-year-as-ceo#:~:text=Feet%20In%20the,petabytes%2C%20after%20all.">genuine source of advantage</a> if you know what to look for. My high-level framework is that being &#8220;native&#8221; (i.e. building from the ground-up with) to a technology should enable you to either:</p><ol><li><p>Deliver an existing feature far better than your competitive set who&#8217;re built on alternative technologies or architectures. E.g. <a href="https://www.sonarsource.com/learn/linter/#:~:text=A%20linter%20will%20scan%20source,in%201978%20at%20Bell%20Labs.">code linters</a> have been a thing for a long time, but Cursor understands what you&#8217;re <em>doing-next</em> vs. do-ing.</p></li><li><p>Offer an entirely new feature that can&#8217;t be provided by your competitive set who&#8217;re built on alternative technologies or architectures. E.g. with a <a href="https://docs.cursor.com/context/@-symbols/@-web">`@web`declaration</a>, Cursor can visit the docs of a given api.  </p></li></ol><p>As is evident from the above, Cursor benefits from both types of &#8220;native&#8221; advantage. Nice. Puff pieces are a little boring though.. so I decided to try and test the limits of Cursor and write something a little more critical (and more constructive, I hope!) by attempting to build <a href="https://nextjs.org/conf">Next.js Conf&#8217;s</a> beautiful new website (partially built by my talented friend <a href="https://ar.linkedin.com/in/facundo-santana-69053459">Facundo</a>) without writing a line of code myself.</p><p>Below is a stream of product observations and requests derived from this experiment. Enjoy! Critique! Frame on your wall! Oh &amp; say hi if you like: alex@tapestry.vc</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">tab tab tab subscribe tab tab tab</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><strong>Observation 1 - 80% feels like 100%</strong></p><p>Typically, when we read our <a href="https://www.independent.ie/regionals/wexford">favourite newspapers</a> we find them insightful. But, have you noticed that when the publication writes about something you consider yourself an &#8220;expert&#8221; on their perspective is a little.. lacking?</p><p>This same phenomenon seems to be occurring with Cursor. For someone that&#8217;s never built a navbar before, doing so with a single prompt is an absolute <em>game-changer (just ask <a href="https://www.reddit.com/r/cursor/comments/1faf2rw/comment/llv9n4m/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">Positive_Box_69</a>)</em>. But, it took me 10+ prompts to get my navbar remotely close to <a href="https://nextjs.org/conf">Next.js&#8217;</a> (&amp; I&#8217;ve built a few too many navbars in my time). For the uninitiated, getting 80% of the way there feels like they&#8217;ve <a href="https://www.youtube.com/watch?v=0TWYcQ8tAKg">completed it mate</a>. </p><p>Now, perhaps I&#8217;m a poor <a href="https://www.cursor.com/blog/prompt-design">prompt designer</a>. So, see below my system prompt or, <a href="https://docs.cursor.com/context/rules-for-ai">&#8220;Rules for AI&#8221;</a> (note the use of role-playing), as well as my attempt to create said navbar via <a href="https://www.promptingguide.ai/techniques/cot">Chain-of-Thought</a> prompting. </p><p>Note: I&#8217;m sure there are many ways that I could improve my prompt (e.g. specifying the inclusion of Next.js <a href="https://vercel.com/font">&#8220;Geist&#8221;</a> font) but as you&#8217;ll see below, my prompt is reasonably extensive.</p><pre><code>// Rules for AI

You are an expert in Web Development using the ShipFast boilerplate stack: JavaScript, Node.js, React, Next.js App Router, Tailwind
CSS, DaisyUl, NextAuth, MongoDB and Mongoose.

Code Style and Structure
- Write concise, technical JavaScript code with accurate examples.
- Use functional and declarative programming patterns; avoid classes.
- Prefer iteration and modularization over code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).

- Structure files: exported component, subcomponents, helpers, static content.

Naming Conventions
- Use kebab-case for directories.
- Use camelCase for variables and functions.
- Use PascalCase for components.
- File names for components should be in PascalCase. Rest of the files in kebab-case.
- Prefix component names with their type (e.g. ButtonAccount.jsx and ButtonSignin.jsx, CardAnalyticsMain jsx and CardAnalyticsData.jsx, etc.)

Syntax and Formatting
- Use the "function" keyword for pure functions.
- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
- Use declarative JSX.

Ul and Styling
- Use DaisyUl and Tailwind CSS for components and styling.
- Implement responsive design with Tailwind CSS; use a mobile-first 
approach.

Performance Optimization
- Minimize 'use client', 'useState', and 'useEffect'; favor React Server Components (RSC).
- Wrap client components in Suspense with fallback.
- Use dynamic loading for non-critical components.
- Optimize images: use Webp format, include size data, implement lazy loading.

Key Conventions
- Optimize Web Vitals (LCP, CLS, FID).
- Limit 'use client':
- Favor server components and Next.js SSR.
- Use only for Web API access in small components.
- Avoid for data fetching or state management</code></pre><pre><code>// Prompt
// Includes screenshot of the navbar from next.js site

I would like for you to recreate the image I have attached to this prompt.

Context:
- We currently have a "default" next.js site that's generated by running 'npx create-next-app@latest'.
- We're using an "src" file with @layout.js and @page.js .
- The image is of a "navbar" on the @https://nextjs.org/conf website.

Instructions:
1. Let's start from left to right on the navbar elements. Describe the navbar image.
2. Describe each element within the navbar. Including the elements' colors, specific shapes, likely border radii in pixels, etc.
3. First, create the "Next.js" text and the div that contains the "CONF24" text. The div should have a black border of .5px.
4. This "Next.js" text and div should be aligned left, about a "third" of the way across the page.
5. Next, create the "box" (a "short" rectangle) that contains the text "/". The border color of the box should be light grey.
6. Ensure that this "box" is at the centre of the navbar.
7. Next to this "box" should be the text "CHAT".
8. The "NEXT.JS On [insert black triangle]", "LOG IN" text should be aligned right. In the final "third" of the page.  
9. Finally, there should be a button to the right of the "LOG IN" text. It should have a dark blue background color, its border should be transparent with a 0px radius, its text should read "GET TICKETS" and the text's color should be white.
10. Please note that next to the "GET TICKETS" text is a white arrow with a circle around it with a white border color.   </code></pre><p>See my result <a href="https://cursor-ex-2.vercel.app/">here</a>. I mean, it&#8217;s pretty impressive, but it&#8217;s about &#8220;20%&#8221; off of the end result. Would I be able to discern where it&#8217;s wrong if: 1) if I didn&#8217;t have a reference image, and more importantly, 2), if I wasn&#8217;t comfortable with frontend dev? Would I have the &#8220;vocabulary&#8221; to make small padding or margin refinements? It&#8217;d be tricky.</p><p><strong>Observation 2 - Cursor is nothing without its <a href="https://x.com/OpenAI/status/1727236805182026159?lang=en-GB"><s>people</s></a> models</strong></p><p>Stripe is an <em>incredibly</em> important piece of infrastructure for <em>many</em> companies <a href="https://x.com/patrickc/status/1833648360194265318">new</a> and old. But, if you asked me to describe, say, <a href="https://stripe.com/gb/customers/linear">Linear&#8217;s</a> core value props, I likely wouldn&#8217;t throw &#8220;payment processing&#8221; into the mix. </p><p>Perhaps when describing something like Airbnb I would allude to <a href="https://customers.twilio.com/en-us/airbnb">Twilio&#8217;s involvement</a>, but again, is receiving a text message about your upcoming stay in Azenhas do Mar what makes you use or switch over to Airbnb? Unlikely.  </p><p>There is, however, a class of companies where their underlying infrastructure is a <em>core component </em>of the product experience: Vimeo is a video platform that <a href="https://www.mux.com/">uses Mux</a>, Tide is a bank that leverages <a href="https://clear.bank/">ClearBank</a>. This isn&#8217;t necessarily a bad <em>product</em> trait, although it can increase a <em>company&#8217;s</em> platform or <a href="https://x.com/HarryStebbings/status/1779910562362654728">&#8220;steamroll&#8221;</a> risk.   </p><p>Cursor, and many LLM-native companies fall into this bucket. So much so that when folk say <em><a href="https://www.youtube.com/watch?v=2fHPB_6ZXvM">&#8220;Cursor helped me build X&#8221;</a></em> they should be passing at least ~50% of this praise onto Claude et al. Though, Cursor is already astutely addressing this risk with <a href="https://docs.cursor.com/advanced/models#:~:text=cursor%2Dsmall%20is%20Cursor%E2%80%99s%20custom%20model%20that%20isn%E2%80%99t%20as%20smart%20as%20GPT%2D4%2C%20but%20is%20faster%20and%20users%20have%20unlimited%20access%20to%20it.">cursor small</a>.    </p><p>As the company continues to add product depth by focusing on some v interesting problems <a href="https://www.cursor.com/blog/problems-2024">[1]</a><a href="https://www.cursor.com/blog/problems-2023">[2]</a> I think this 50% attribution rate will begin to shift. In fact, Cursor&#8217;s increasing ability to inject the <a href="https://www.cursor.com/blog/problems-2024#:~:text=flow%20async%20edits-,Optimal%20Context,-There%20can%20be">&#8220;Optimal Context&#8221;</a> into LLMs may end up flipping their relationship with LLM providers on its head. Will be an interesting watch.</p><p><strong>Observation 3 -</strong> <strong>In-Context Editing</strong></p><p>When working on my Next.js clone I often found myself hopping into Cursor Chat to make minor edits (think changing padding, easing animations, etc). As someone that&#8217;s very comfortable with CSS this was strange, why didn&#8217;t I just change 1px to 2px or #87CEEB to #000080? </p><p>The thing is, you kinda get used to &#8220;writing code&#8221; in English, so my instinct was to continue to do so: <em>&#8220;move that div a little to the left&#8221;</em>. This isn&#8217;t a big deal when you&#8217;re familiar with the language/library that you&#8217;re using as you have the vocab: <em>&#8220;move the &lt;div className=&#8221;example&#8221;&gt; 10px to the left&#8221;</em>, or, if all else fails, you can just jump into the code and fix things.</p><p>But what if you don&#8217;t have the words? If someone has never worked with <a href="http://three.js">three.js</a> before, they&#8217;ll have no clue how &#8220;alphaMap&#8221; impacts the opacity of their 3D object. Thankfully, three.js (&amp; more specifically, lil-gui) might <a href="https://lil-gui.georgealways.com/">suggest an answer</a> here.</p><p>lil-gui allows you to edit certain variables graphically so that you build a sense for how they impact your 3D scene: <a href="https://threejs.org/examples/#webgl_animation_skinning_morph">threejs.org/examples/#webgl_animation_skinning_morph</a>.</p><p>What if Cursor could generate similar &#8220;<a href="https://machinelearning.apple.com/research/biscuit-scaffolding-llm">ephemeral</a>&#8221; and/or &#8220;<a href="https://x.com/OrionReedOne/status/1805680561215914207">malleable</a>&#8221; UIs, but in real-time? Having <em>briefly </em>thought about how you&#8217;d scale this, it seems plausible given that Cursor <a href="https://docs.cursor.com/context/@-symbols/@-docs">can crawl</a> third party docs, etc. This would be very cool.</p><p><strong>Observation 4 - Selective Memory</strong></p><p>Admittedly, I thought that Bill Gurley was erring on the side of bloviation when discussing the memory challenges of SOTA models <a href="https://youtu.be/iTwZzUApGkA?si=gUj9vtKg6VBHB9zy">[1]</a><a href="https://youtu.be/bD1rrBBcJSA?si=FUi0Rh-dkdUJcdzK">[2]</a><a href="https://youtu.be/oHYoSBixdPI?si=hMFsY9h8Zrzgt2W6">[3]</a>. Unsurprisingly, he&#8217;s totally right. But I&#8217;ll add one slight caveat &#8212; LLMs have &#8220;selective memory&#8221;.  </p><p>Let&#8217;s dig into some examples. I was recently working with Twitter&#8217;s API (which, btw, is now <em><a href="https://developer.x.com/en/products/x-api/enterprise/enterprise-api-interest-form#:~:text=Enterprise%20API%20pricing%20starts%20at,based%20on%20usage%20and%20needs.">extortionate</a></em>) and authenticated via <a href="https://oauth.net/2/">OAuth 2.0</a>. Sweet, all was going great. But, as I iterated through other errors within my codebase, I ran into an auth issue. Odd? </p><p>At some point, the LLM decided to replace my OAuth 2.0 boilerplate with OAuth 1.0. I.e. the model, despite having the context that Cursor provides, &#8220;forgot&#8221; that I strictly asked for it to work within the OAuth 2.0 spec. This is likely due to the bulk of twitter API code on the internet using OAuth 1.0 (Twitter&#8217;s <a href="https://developer.x.com/en/docs/x-api/getting-started/about-x-api">V2 endpoint</a> that uses OAuth 2.0 was only released in 2021). </p><p>Now, before anyone says it. Yes, I did accept the change that Cursor suggested, so the blame is <em>technically</em>, on me, but either way, the code suggested was incorrect. <em>I&#8217;m only human, and perhaps LLMs are too.</em></p><p>What do I mean by &#8220;selective&#8221; though? Well, I&#8217;ve found that there are certain prompts/instructions that models treat as sacrosanct, even as your latter prompts contradict them (or even cancel them out entirely). In these cases, the model&#8217;s long-term memory is nearly &#8220;too good&#8221;.</p><p><strong>Observation 5 - Local Optimum Loop (LOL)</strong></p><p>I was trading notes on Cursor with a friend who summed up my own experience pretty well:</p><p><em>&#8220;I've had similar experiences with trying to do complex animations. Very easy for the output to get stuck in a local optimum and just loop. I find that I often have to "jump start" it by rewriting the existing code more significantly.&#8221;</em></p><p>For me, this issue was most apparent when attempting to implement the &#8220;<a href="https://nextjs.org/conf">NEXT grid</a>&#8221;. Cursor did a truly awesome job of creating a crude &#8220;NEXT&#8221; outline by using <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout">CSS grid</a>, but no matter what I tried (including using three.js instead), it couldn&#8217;t get anywhere near the finished product. Instead, I entered the &#8220;loop&#8221; described above.</p><p>Given my &#8220;experiment&#8221; involved writing no code myself, my attempt at &#8220;jump starting&#8221; the LLM came via narrowing the aperture of the task. So, my prompt went from detailing how the entire &#8220;NEXT&#8221; grid should look, to focusing on a single letter, and eventually, a single square within a letter. </p><p>This approach initially improved results, but its efficacy decayed and I gradually found myself back at the &#8220;local optimum loop&#8221;. This did get me thinking about how much I still have to learn about prompting though!  </p><div><hr></div><p>Ok, that&#8217;s a wrap to my &#8220;addendum&#8221; of problems that I&#8217;m <a href="http://the problems">equally excited</a> to see Cursor solve. <a href="https://www.cursor.com/blog/problems-2023#:~:text=Never%20worry%20about%20stack%20traces%20again%3A%20The%20IDE%20should%20just%20get%20it%2C%20and%20auto%2Dfix%20the%20code%20for%20you.">Never having</a> to read a wall of stack traces again sounds like a pretty ideal end state to me. I&#8217;d love to say hi/spar with others who&#8217;ve been playing around with Cursor: <em>alex@tapestry.vc</em>. Thanks for reading, folk.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Observation 6 - You Should Subscribe</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><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Flox]]></title><description><![CDATA[Containers, without containers]]></description><link>https://whynowtech.substack.com/p/flox</link><guid isPermaLink="false">https://whynowtech.substack.com/p/flox</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Wed, 07 Aug 2024 15:13:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!tBhE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p>Whilst it&#8217;s not required, if you want to follow along, you can install Flox in an instant <a href="https://flox.dev/docs/">here</a>.</p><p>Oh and thanks for the 1k subs. Pretty cool!</p></div><p>What&#8217;s cool about technology investing is that amongst all the hysteria, there are technologies out there, laying in plain sight, that are <em>criminally </em>underrated. I <a href="https://whynowtech.substack.com/p/tracebit-going-from-the-top-1-to">recently pointed</a> to canaries as but one example, but let&#8217;s not forget that the transformer was hanging around ~5 years before ChatGPT.   </p><p>Today, dear readers, I&#8217;m going to layout why I think that the world&#8217;s 20 million-something developers (not to mention agents) will, eventually, <em>all</em> be using <a href="https://flox.dev/">Flox</a>.</p><p>Some background: I personally use Flox for every project, pretty much everyday, and I can&#8217;t think of a reason why I would pick Docker over it. This is <a href="https://flox.dev/blog/flaim">particularly true</a> when running AI models locally.</p><p>Even better, I don&#8217;t use Flox for just one task. The reason why <a href="https://whynowtech.substack.com/p/nix">Nix</a> (Flox&#8217;s underlying technology) is <a href="https://x.com/tobi/status/1576268144351399936">infamously</a> difficult to grok is that it is many things. If anything, Nix is more of a philosophy, an opinion. Thankfully, Flox takes those many things and makes them a little more.. approachable.</p><p>Want a reproducible developer environment like Python&#8217;s venv or Conda? Cool, Flox can do that, but like, it actually works. Want a package manager like npm? Yeah, Flox does that better too. Want to build packages? Again, Flox is the correct way to do this. </p><p>Even better, Flox passes Sergey Brin&#8217;s <a href="https://www.youtube.com/watch?v=cLVdsZ3I5os">&#8220;toothbrush test&#8221;</a>. It&#8217;s something that <em>every</em> developer should use <em>every </em>hour of <em>every</em> day. Products with these characteristics, naturally, capture our attention at <a href="https://www.tapestry.vc/">Tapestry</a>. </p><p>So, dear readers, my gift to thee is to: 1) explain why I feel so strongly and 2) help you install Flox yourselves. Yeno, if that&#8217;s your kinda thing.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Join 1k+ fine folk in subscribing?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Alright, so something a few of you enjoyed during my piece on <a href="https://whynowtech.substack.com/p/restate-and-durable-execution">Restate &amp; Durable Execution</a> is when I explained Restate through sections of their website. I figured that with a website as pretty as Flox&#8217;s, it&#8217;d be rude not to flaunt it a little too: <a href="http://flox.dev">flox.dev</a> </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tBhE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tBhE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png 424w, https://substackcdn.com/image/fetch/$s_!tBhE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png 848w, https://substackcdn.com/image/fetch/$s_!tBhE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png 1272w, https://substackcdn.com/image/fetch/$s_!tBhE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tBhE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png" width="1456" height="763" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89d1277c-88db-4767-b008-e78babd26d66_1478x775.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:763,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:300046,&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_!tBhE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png 424w, https://substackcdn.com/image/fetch/$s_!tBhE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png 848w, https://substackcdn.com/image/fetch/$s_!tBhE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.png 1272w, https://substackcdn.com/image/fetch/$s_!tBhE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89d1277c-88db-4767-b008-e78babd26d66_1478x775.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>Ok, so firstly.. what is a &#8220;dev environment?&#8221;. </p><p>As developers, we use <em>a tonne </em>of third party software. For example, instead of writing the raw python code to do some specific Tapestry VC portfolio data analysis, I might use a third party library or &#8220;dependency&#8221; like <a href="https://pandas.pydata.org/">Pandas</a>. </p><p>To use Pandas on my &#8220;machine&#8221; (i.e. laptop), I need to install it. If it&#8217;s not there already of course. I typically do this with a <em>python-specific</em> (take note, this is important later) package manager like <a href="https://pypi.org/project/pip/">Pip</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LgPT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LgPT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 424w, https://substackcdn.com/image/fetch/$s_!LgPT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 848w, https://substackcdn.com/image/fetch/$s_!LgPT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 1272w, https://substackcdn.com/image/fetch/$s_!LgPT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LgPT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png" width="1182" height="32" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:32,&quot;width&quot;:1182,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15482,&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_!LgPT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 424w, https://substackcdn.com/image/fetch/$s_!LgPT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 848w, https://substackcdn.com/image/fetch/$s_!LgPT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 1272w, https://substackcdn.com/image/fetch/$s_!LgPT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4bf2109-2761-433f-b786-ee93670cd7d9_1182x32.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Alas, this is where my problems begin. Look at what happens when I run the above command in my terminal:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N3ZT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N3ZT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 424w, https://substackcdn.com/image/fetch/$s_!N3ZT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 848w, https://substackcdn.com/image/fetch/$s_!N3ZT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 1272w, https://substackcdn.com/image/fetch/$s_!N3ZT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N3ZT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png" width="1456" height="49" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:49,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32465,&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_!N3ZT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 424w, https://substackcdn.com/image/fetch/$s_!N3ZT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 848w, https://substackcdn.com/image/fetch/$s_!N3ZT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 1272w, https://substackcdn.com/image/fetch/$s_!N3ZT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09c36293-3dee-4ced-88c4-fe168074a900_2726x92.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>It turns out that when we install the Pandas library, we&#8217;re also installing specific &#8220;versions&#8221; of other libraries that Pandas itself relies on. In this instance, we see that Pandas &#8220;requires&#8221; <a href="https://numpy.org/">Numpy</a>. Specifically, it requires any version of Numpy that is greater than 1.22.4 but less than 2.0.0. </p><p>Hmm. But what happens if I have the latest version of Numpy (which is 2.0.0) installed on my system already? I.e. before I installed Pandas. Then we&#8217;re in trouble. Why? Well, if we then install Pandas, we now have two versions of Numpy on our machines. C&#8217;est tr&#232;s probl&#233;matique. </p><p>What&#8217;s the problem? Well, how does my machine know what version of Numpy it should use for my new project? Whilst we do have some smart ways of &#8220;resolving&#8221; these &#8220;dependency conflicts&#8221;, we still often run into issues. I assure you, there is <a href="https://stackoverflow.com/questions/tagged/conflict?tab=Newest">nothing more frustrating</a> than dependency conflicts as a developer.</p><p>This is a problem that <em>every </em>developer runs into, and hence, one where <em>every</em> developer needs some solution. This is where &#8220;developer environments&#8221; kick in. You&#8217;ve probably heard of a few of these guys in the past: <a href="https://docs.python.org/3/library/venv.html">venv</a>, <a href="https://pipenv.pypa.io/en/latest/">pipenv</a>, <a href="https://conda.io/projects/conda/en/latest/user-guide/getting-started.html">conda</a>, <a href="https://github.com/nvm-sh/nvm">nvm</a>, <a href="https://rvm.io/">rvm</a>, etc. When you learn to code in Python, venv is likely one of the first three tools you pick up. Let&#8217;s &#8216;av a look at how venv works:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3qX-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3qX-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 424w, https://substackcdn.com/image/fetch/$s_!3qX-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 848w, https://substackcdn.com/image/fetch/$s_!3qX-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 1272w, https://substackcdn.com/image/fetch/$s_!3qX-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3qX-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png" width="1456" height="27" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:27,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20185,&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_!3qX-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 424w, https://substackcdn.com/image/fetch/$s_!3qX-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 848w, https://substackcdn.com/image/fetch/$s_!3qX-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 1272w, https://substackcdn.com/image/fetch/$s_!3qX-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10002cdc-0eae-43f4-bb0c-84c5135382a2_1696x32.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ok, so, here I&#8217;ve just created a developer or &#8220;virtual&#8221; environment and called it &#8220;myenv&#8221;. Let&#8217;s now &#8220;activate&#8221; this environment and then I&#8217;ll explain what this accomplishes:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FDZ3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FDZ3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 424w, https://substackcdn.com/image/fetch/$s_!FDZ3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 848w, https://substackcdn.com/image/fetch/$s_!FDZ3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 1272w, https://substackcdn.com/image/fetch/$s_!FDZ3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FDZ3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png" width="1456" height="37" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b9266f1-355c-498c-a293-51050b491c21_1812x46.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:37,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22833,&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_!FDZ3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 424w, https://substackcdn.com/image/fetch/$s_!FDZ3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 848w, https://substackcdn.com/image/fetch/$s_!FDZ3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 1272w, https://substackcdn.com/image/fetch/$s_!FDZ3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b9266f1-355c-498c-a293-51050b491c21_1812x46.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Exa3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Exa3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 424w, https://substackcdn.com/image/fetch/$s_!Exa3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 848w, https://substackcdn.com/image/fetch/$s_!Exa3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 1272w, https://substackcdn.com/image/fetch/$s_!Exa3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Exa3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png" width="1452" height="58" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:58,&quot;width&quot;:1452,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20487,&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_!Exa3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 424w, https://substackcdn.com/image/fetch/$s_!Exa3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 848w, https://substackcdn.com/image/fetch/$s_!Exa3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 1272w, https://substackcdn.com/image/fetch/$s_!Exa3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F403817c7-d7c8-4c91-a95e-309efb7af392_1452x58.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Cool, I&#8217;m now &#8220;inside&#8221; my developer environment called &#8220;myenv&#8221;. Just think of developer environments as folders that store the dependencies a specific project requires. See below that &#8220;myenv&#8221; is a folder in the `whynow_code_examples` directory alongside some other Why Now folders <a href="https://whynowtech.substack.com/p/post-transformers-hyena-hierarchy">[1]</a><a href="https://whynowtech.substack.com/p/secure-enclaves">[2]</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jBu3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jBu3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 424w, https://substackcdn.com/image/fetch/$s_!jBu3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 848w, https://substackcdn.com/image/fetch/$s_!jBu3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 1272w, https://substackcdn.com/image/fetch/$s_!jBu3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jBu3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png" width="1456" height="86" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:86,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:27819,&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_!jBu3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 424w, https://substackcdn.com/image/fetch/$s_!jBu3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 848w, https://substackcdn.com/image/fetch/$s_!jBu3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 1272w, https://substackcdn.com/image/fetch/$s_!jBu3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F006c51a8-3b86-409d-a830-f9df935cfd3d_1516x90.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Within these environments, when we install packages like Pandas, they&#8217;re &#8220;isolated&#8221; or &#8220;contained&#8221; (sound familiar?) within the directory of our project. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5lIY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5lIY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 424w, https://substackcdn.com/image/fetch/$s_!5lIY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 848w, https://substackcdn.com/image/fetch/$s_!5lIY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 1272w, https://substackcdn.com/image/fetch/$s_!5lIY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5lIY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png" width="1456" height="230" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:230,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:94643,&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_!5lIY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 424w, https://substackcdn.com/image/fetch/$s_!5lIY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 848w, https://substackcdn.com/image/fetch/$s_!5lIY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 1272w, https://substackcdn.com/image/fetch/$s_!5lIY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8746c99c-bb0a-4901-9c9a-d49beb8f8ff4_1846x292.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Hence, this time when I run `pip3 install pandas` my terminal doesn&#8217;t tell me that the requirement of Numpy is &#8220;already satisfied&#8221;. Why? Well, my developer environment is isolated. It doesn&#8217;t have access to dependencies that are installed elsewhere. Thus, there&#8217;s no (or at least, less) room for dependency conflicts! Nice. </p><p>Ok, we&#8217;ve made <em>a lot</em> of progress here. One final thing to understand about developer environments is that they&#8217;re intended to be &#8220;portable&#8221;. I as <em>SickSoftwareEng34 </em>want to ensure that my esteemed peer <em>BasedDev22 </em>can successfully run the software that I&#8217;ve written, on their machine also. </p><p>In order to do this, they need to &#8220;reproduce&#8221; the <em>exact</em> developer environment that&#8217;s on my machine, on their own machine. I.e. they need specific versions of Pandas, Numpy, etc. </p><p>When using venv, and many other developer environments, we achieve this by using a requirements.txt file. Let me show you how:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P_po!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P_po!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 424w, https://substackcdn.com/image/fetch/$s_!P_po!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 848w, https://substackcdn.com/image/fetch/$s_!P_po!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 1272w, https://substackcdn.com/image/fetch/$s_!P_po!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P_po!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png" width="1456" height="284" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:284,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56125,&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_!P_po!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 424w, https://substackcdn.com/image/fetch/$s_!P_po!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 848w, https://substackcdn.com/image/fetch/$s_!P_po!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 1272w, https://substackcdn.com/image/fetch/$s_!P_po!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F74cda0a5-4f0f-401e-becc-dda0d92188b6_1528x298.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Running `pip3 freeze` within my terminal outputs all of the dependencies installed by pip within a given directory (in this case, our developer environment). We can then save, or &#8220;pipe&#8221;, the output of this command to a text file like so:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!w9vm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!w9vm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 424w, https://substackcdn.com/image/fetch/$s_!w9vm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 848w, https://substackcdn.com/image/fetch/$s_!w9vm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 1272w, https://substackcdn.com/image/fetch/$s_!w9vm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!w9vm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png" width="1456" height="28" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:28,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23095,&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_!w9vm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 424w, https://substackcdn.com/image/fetch/$s_!w9vm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 848w, https://substackcdn.com/image/fetch/$s_!w9vm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 1272w, https://substackcdn.com/image/fetch/$s_!w9vm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8dd1201e-7314-43a1-8a46-71d0f1e0e076_1896x36.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ok sweet, we now have a `requirements.txt` file that contains the `pip3 freeze` output: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DfF6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DfF6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png 424w, https://substackcdn.com/image/fetch/$s_!DfF6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png 848w, https://substackcdn.com/image/fetch/$s_!DfF6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png 1272w, https://substackcdn.com/image/fetch/$s_!DfF6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DfF6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png" width="1446" height="532" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:532,&quot;width&quot;:1446,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77788,&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_!DfF6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png 424w, https://substackcdn.com/image/fetch/$s_!DfF6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png 848w, https://substackcdn.com/image/fetch/$s_!DfF6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.png 1272w, https://substackcdn.com/image/fetch/$s_!DfF6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdce6b79d-1154-4d0b-b0f8-a83236326aee_1446x532.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>Things are quite simple from here. I can then share this file with <em>BasedDev22, </em>they&#8217;ll run `pip3 install -r requirements.txt` et voil&#224;, they&#8217;ll install the exact* same dependencies in their environment.</p><div><hr></div><p>*Of course, I wouldn&#8217;t be writing this primer on Flox if things worked so.. swimmingly. Tools like venv are <em>far</em> from complete. </p><p>First up in the case of <em>Alex Mackenzie vs. venv, 2024 </em>is that venv isn&#8217;t a package manager (yep, I said it). I need to use a separate tool, pip, when installing packages. I&#8217;m aware that this may sound a little pedantic.. but I&#8217;d prefer a consolidated toolset here.</p><p>Next, venv is language-specific. If I&#8217;m writing a node-based (i.e. JavaScript) web app, I can&#8217;t manage my JavaScript dependencies with venv. As a developer this is a PITA, as it means that I have to use an alternate tool for JS et al. <em>Habits aren&#8217;t formed this way.</em> </p><p>More generally, other language-specific environment or package managers like <a href="https://www.npmjs.com/">npm</a> (JavaScript), <a href="https://doc.rust-lang.org/book/ch01-03-hello-cargo.html">Cargo</a> (Rust) and <a href="https://rubygems.org/">RubyGems</a> (Ruby) are similarly not language-agnostic. </p><p>Finally, package managers like npm et al can&#8217;t install &#8220;system-level&#8221; dependencies (e.g. compilers or other utilities). For this, we need to use <em>other </em>package managers like <a href="https://brew.sh/">Homebrew</a> for macOS or <a href="https://ubuntu.com/server/docs/package-management">APT</a> for Linux. Again, I hope the fragmented toolchain is overt here.  </p><p>Ok, so to sum up our current woes as developers just tryin&#8217; to get our jobs done: </p><ul><li><p>Language-specific package managers like pip or npm aren&#8217;t versatile enough to accommodate the other programming languages I use.</p></li><li><p>Language-specific package managers can&#8217;t install the system-level dependencies I often need to install.</p></li><li><p>Many environment managers aren&#8217;t package managers (venv), many package managers aren&#8217;t environment managers (Homebrew). </p></li></ul><p>My real &#8220;a ha!&#8221; moment was when I realised that Flox (or, Nix) solves all of the above challenges (&amp; some other pretty gnarly ones). As mentioned, you can <a href="https://flox.dev/docs/">install Flox</a> in an instant if you want to follow along below. It&#8217;s totally fine to follow along without doing so too.</p><p>Alright, I&#8217;m now back in my `whynow_code_examples` directory:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hXuH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hXuH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 424w, https://substackcdn.com/image/fetch/$s_!hXuH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 848w, https://substackcdn.com/image/fetch/$s_!hXuH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 1272w, https://substackcdn.com/image/fetch/$s_!hXuH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hXuH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png" width="1302" height="74" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:74,&quot;width&quot;:1302,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19374,&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_!hXuH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 424w, https://substackcdn.com/image/fetch/$s_!hXuH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 848w, https://substackcdn.com/image/fetch/$s_!hXuH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 1272w, https://substackcdn.com/image/fetch/$s_!hXuH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95dfe025-5570-467e-b4fa-9e3ac12137a2_1302x74.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Let&#8217;s spin up a Flox developer environment with the `flox init` command. This should feel quite familiar as Flox&#8217;s workflow is similar to that of venv&#8217;s:   </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jqhn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jqhn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png 424w, https://substackcdn.com/image/fetch/$s_!jqhn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png 848w, https://substackcdn.com/image/fetch/$s_!jqhn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png 1272w, https://substackcdn.com/image/fetch/$s_!jqhn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jqhn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png" width="1456" height="428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:428,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97601,&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_!jqhn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png 424w, https://substackcdn.com/image/fetch/$s_!jqhn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png 848w, https://substackcdn.com/image/fetch/$s_!jqhn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.png 1272w, https://substackcdn.com/image/fetch/$s_!jqhn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfd4235d-bfed-4aa2-98da-0f4677922793_1558x458.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>Great, I&#8217;ve now created a virtual environment. Let&#8217;s &#8220;activate&#8221; the environment, climb inside it, and then I can show you some of Flox&#8217;s magic:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9u0E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9u0E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 424w, https://substackcdn.com/image/fetch/$s_!9u0E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 848w, https://substackcdn.com/image/fetch/$s_!9u0E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 1272w, https://substackcdn.com/image/fetch/$s_!9u0E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9u0E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png" width="1456" height="199" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:199,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:74470,&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_!9u0E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 424w, https://substackcdn.com/image/fetch/$s_!9u0E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 848w, https://substackcdn.com/image/fetch/$s_!9u0E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 1272w, https://substackcdn.com/image/fetch/$s_!9u0E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabcd9db3-c35c-4e69-bc89-fd1e772859a3_1916x262.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Want to install Python&#8217;s Pandas library? Let&#8217;s do it. Want to install JavaScript&#8217;s Node.js? We can do that too. We can even give Homebrew a run for its money and install a system-level utility like <a href="https://htop.dev/">htop</a>. Flox is both language and platform agnostic:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TUcZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TUcZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 424w, https://substackcdn.com/image/fetch/$s_!TUcZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 848w, https://substackcdn.com/image/fetch/$s_!TUcZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 1272w, https://substackcdn.com/image/fetch/$s_!TUcZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TUcZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png" width="1456" height="323" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:323,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:171128,&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_!TUcZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 424w, https://substackcdn.com/image/fetch/$s_!TUcZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 848w, https://substackcdn.com/image/fetch/$s_!TUcZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 1272w, https://substackcdn.com/image/fetch/$s_!TUcZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F99547fbf-952b-4acc-9e6c-878dc2cebbff_2004x444.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>At this point you should have hopefully realised that Flox is acting as a developer environment too. When we&#8217;re inside our Flox environment, we can run `htop`: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jQNX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jQNX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 424w, https://substackcdn.com/image/fetch/$s_!jQNX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 848w, https://substackcdn.com/image/fetch/$s_!jQNX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 1272w, https://substackcdn.com/image/fetch/$s_!jQNX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jQNX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png" width="1456" height="616" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:616,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:288643,&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_!jQNX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 424w, https://substackcdn.com/image/fetch/$s_!jQNX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 848w, https://substackcdn.com/image/fetch/$s_!jQNX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 1272w, https://substackcdn.com/image/fetch/$s_!jQNX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dbcbde8-8c51-4ff6-b8d7-5317f742dcb4_2032x860.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When we `exit` outside of our Flox environment, we can&#8217;t:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dSaY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dSaY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 424w, https://substackcdn.com/image/fetch/$s_!dSaY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 848w, https://substackcdn.com/image/fetch/$s_!dSaY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 1272w, https://substackcdn.com/image/fetch/$s_!dSaY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dSaY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png" width="1456" height="113" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6664c157-0457-4a71-972a-206059d1d488_1938x150.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:113,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53601,&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_!dSaY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 424w, https://substackcdn.com/image/fetch/$s_!dSaY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 848w, https://substackcdn.com/image/fetch/$s_!dSaY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 1272w, https://substackcdn.com/image/fetch/$s_!dSaY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6664c157-0457-4a71-972a-206059d1d488_1938x150.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Hmm. It would appear to me that Flox has just solved the three problems enumerated above? Furthermore, my workflow used to require an array of tools, now it&#8217;s converging towards just one. Nice work Flox.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yxBx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yxBx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 424w, https://substackcdn.com/image/fetch/$s_!yxBx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 848w, https://substackcdn.com/image/fetch/$s_!yxBx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 1272w, https://substackcdn.com/image/fetch/$s_!yxBx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yxBx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png" width="1456" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:636829,&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_!yxBx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 424w, https://substackcdn.com/image/fetch/$s_!yxBx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 848w, https://substackcdn.com/image/fetch/$s_!yxBx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 1272w, https://substackcdn.com/image/fetch/$s_!yxBx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46fad87d-c883-4bb0-8285-7df412a87236_2360x1134.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TPfR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TPfR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png 424w, https://substackcdn.com/image/fetch/$s_!TPfR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png 848w, https://substackcdn.com/image/fetch/$s_!TPfR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png 1272w, https://substackcdn.com/image/fetch/$s_!TPfR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TPfR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png" width="1456" height="703" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:703,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:488321,&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_!TPfR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png 424w, https://substackcdn.com/image/fetch/$s_!TPfR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png 848w, https://substackcdn.com/image/fetch/$s_!TPfR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.png 1272w, https://substackcdn.com/image/fetch/$s_!TPfR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c2b459b-e9bd-4f93-af4a-f6a5f3fe24b1_2398x1158.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>Next - remember our `requirements.txt` file? Well, you guessed it, with Flox we don&#8217;t need it either. If I want to use a colleague&#8217;s work, I can simply activate their &#8220;remote environment&#8221; (published to FloxHub) and with one-command, their software works flawlessly on my machine (irrespective of my OS). </p><p>Flox&#8217;s Ross Turk created the <a href="https://flox.dev/blog/flaim">FLAIM</a> (Flox AI Modelling) environment that let&#8217;s us run Stable Diffusion locally, so let&#8217;s &#8216;av a bit of fun and do that. Later, we&#8217;ll get into why Flox is <a href="https://flox.dev/blog/flaim#:~:text=In%20the%20first,a%20modest%20proposal.">particularly suited</a> to running AI workloads locally. </p><p>Again, with one command `flox activate -r flox/flaim` we can get to work:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2bgx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2bgx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 424w, https://substackcdn.com/image/fetch/$s_!2bgx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 848w, https://substackcdn.com/image/fetch/$s_!2bgx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 1272w, https://substackcdn.com/image/fetch/$s_!2bgx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2bgx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png" width="1456" height="363" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:363,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:105009,&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_!2bgx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 424w, https://substackcdn.com/image/fetch/$s_!2bgx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 848w, https://substackcdn.com/image/fetch/$s_!2bgx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 1272w, https://substackcdn.com/image/fetch/$s_!2bgx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb65ac0a8-8360-4f6a-9fe5-5ec14bb1af4d_1886x470.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ok, the final test, has Flox installed the exact dependencies that enables Ross&#8217; software to run successfully on my machine?:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cf0U!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cf0U!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 424w, https://substackcdn.com/image/fetch/$s_!cf0U!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 848w, https://substackcdn.com/image/fetch/$s_!cf0U!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 1272w, https://substackcdn.com/image/fetch/$s_!cf0U!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cf0U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png" width="1456" height="69" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:69,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34771,&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_!cf0U!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 424w, https://substackcdn.com/image/fetch/$s_!cf0U!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 848w, https://substackcdn.com/image/fetch/$s_!cf0U!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 1272w, https://substackcdn.com/image/fetch/$s_!cf0U!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3adfb8f5-8cff-4fbb-871c-ee5afcb02c72_1946x92.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V_JD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V_JD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png 424w, https://substackcdn.com/image/fetch/$s_!V_JD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png 848w, https://substackcdn.com/image/fetch/$s_!V_JD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png 1272w, https://substackcdn.com/image/fetch/$s_!V_JD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V_JD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png" width="1456" height="686" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:686,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:843975,&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_!V_JD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png 424w, https://substackcdn.com/image/fetch/$s_!V_JD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png 848w, https://substackcdn.com/image/fetch/$s_!V_JD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.png 1272w, https://substackcdn.com/image/fetch/$s_!V_JD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F542f5143-8967-4574-8e8c-f2c9ac29e512_1792x844.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>I mean, it&#8217;s not exactly the <a href="https://www.irishcentral.com/roots/history/ireland-emerald-isle">Emerald Isle&#8217;s</a> tricolour, but hey, that&#8217;s Stable Diffusion&#8217;s problem. Ross&#8217; software was successfully &#8220;reproduced&#8221; on my machine (macOS) and it&#8217;d run just as successfully on any Linux distribution. Now we can truly &#8220;write once, run anywhere&#8221;. </p><div><hr></div><p>Now is when the dude in the back of the room, often with a long grey beard, usually asks: &#8220;what about Docker?&#8221;. A fair question. This is where things get particularly interesting, and where Nix really comes into a league of its own.</p><p>Firstly, we need to level set on Docker. <a href="https://www.docker.com/">Docker</a>, and the technology they democratised, containers, achieves comparable levels of isolation, reproducibility and portability to that of Flox / Nix. Shall we familiarise ourselves with an example?:</p><p>First, let&#8217;s log into &#8220;Docker Hub&#8221; (<a href="https://hub.docker.com/">hub.docker.com</a>) and find a Docker &#8220;Image&#8221; that we want to &#8220;pull&#8221;. Docker Images are essentially developer environments, they describe the dependencies a given project requires, as well as some other important metadata like a project&#8217;s filesystem, etc.  </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BBI_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BBI_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 424w, https://substackcdn.com/image/fetch/$s_!BBI_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 848w, https://substackcdn.com/image/fetch/$s_!BBI_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 1272w, https://substackcdn.com/image/fetch/$s_!BBI_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BBI_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png" width="1456" height="150" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:58547,&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_!BBI_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 424w, https://substackcdn.com/image/fetch/$s_!BBI_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 848w, https://substackcdn.com/image/fetch/$s_!BBI_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 1272w, https://substackcdn.com/image/fetch/$s_!BBI_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582b08db-c796-4c38-a6d5-ba757a7f8c99_1984x204.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ok, cool, I&#8217;m logged into Docker Hub via my CLI. Next, much like when using Flox, I&#8217;ll search for a piece of software I want to reproduce and get to work via `docker search pandas`:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cQGx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cQGx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 424w, https://substackcdn.com/image/fetch/$s_!cQGx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 848w, https://substackcdn.com/image/fetch/$s_!cQGx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 1272w, https://substackcdn.com/image/fetch/$s_!cQGx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cQGx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png" width="1456" height="202" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:202,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57786,&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_!cQGx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 424w, https://substackcdn.com/image/fetch/$s_!cQGx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 848w, https://substackcdn.com/image/fetch/$s_!cQGx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 1272w, https://substackcdn.com/image/fetch/$s_!cQGx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb989a89d-f34f-4cf0-b1bf-938125ab33a6_1976x274.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Ugh, I receive an error message. We&#8217;ll dissect this in a second, but note, I don&#8217;t run into this issue when using Flox:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2O8D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2O8D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 424w, https://substackcdn.com/image/fetch/$s_!2O8D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 848w, https://substackcdn.com/image/fetch/$s_!2O8D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 1272w, https://substackcdn.com/image/fetch/$s_!2O8D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2O8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png" width="1456" height="205" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:205,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84826,&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_!2O8D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 424w, https://substackcdn.com/image/fetch/$s_!2O8D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 848w, https://substackcdn.com/image/fetch/$s_!2O8D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 1272w, https://substackcdn.com/image/fetch/$s_!2O8D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9076d803-50d8-4882-94f0-905c3ab26cd3_1976x278.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Many of you who&#8217;re avid Docker users will immediately call me out on my bullshit (rightly so), but this is but one of many examples of working with Flox being just a little less cumbersome than Docker. </p><p>Let&#8217;s resolve this issue by running <a href="https://www.docker.com/products/docker-desktop/">&#8220;Docker Desktop&#8221;</a> (yes, a separate app I need to install on macOS / Windows..) which is the &#8220;Docker daemon&#8221; that wasn&#8217;t running previously. </p><p>Now all works perfectly fine when I run `docker search pandas` (a Python library), `docker search nodejs` (a JavaScript library) or, our pal,`docker search htop` (a system utility). Much like Flox, Docker is language and platform agnostic. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GnkP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GnkP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png 424w, https://substackcdn.com/image/fetch/$s_!GnkP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png 848w, https://substackcdn.com/image/fetch/$s_!GnkP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png 1272w, https://substackcdn.com/image/fetch/$s_!GnkP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GnkP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png" width="1456" height="436" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:436,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:148008,&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_!GnkP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png 424w, https://substackcdn.com/image/fetch/$s_!GnkP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png 848w, https://substackcdn.com/image/fetch/$s_!GnkP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.png 1272w, https://substackcdn.com/image/fetch/$s_!GnkP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd73bf70b-efc6-4dbc-9ccf-ab07f91f7f68_1996x598.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>Next, I&#8217;ll pull the Pandas Image I want and get to work: </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vatz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vatz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 424w, https://substackcdn.com/image/fetch/$s_!Vatz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 848w, https://substackcdn.com/image/fetch/$s_!Vatz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 1272w, https://substackcdn.com/image/fetch/$s_!Vatz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vatz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png" width="1456" height="65" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:65,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30859,&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_!Vatz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 424w, https://substackcdn.com/image/fetch/$s_!Vatz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 848w, https://substackcdn.com/image/fetch/$s_!Vatz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 1272w, https://substackcdn.com/image/fetch/$s_!Vatz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e2a7c25-3c98-444c-af14-d649910686dd_1928x86.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l0xc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l0xc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 424w, https://substackcdn.com/image/fetch/$s_!l0xc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 848w, https://substackcdn.com/image/fetch/$s_!l0xc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 1272w, https://substackcdn.com/image/fetch/$s_!l0xc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l0xc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png" width="1456" height="143" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:143,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45529,&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_!l0xc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 424w, https://substackcdn.com/image/fetch/$s_!l0xc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 848w, https://substackcdn.com/image/fetch/$s_!l0xc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 1272w, https://substackcdn.com/image/fetch/$s_!l0xc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f1f332b-d037-4c98-af4d-7544aae4fcc8_1954x192.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I&#8217;m now running a shell within my Docker &#8220;container&#8221;. Within it, I have comparable levels of &#8220;isolation&#8221; to that of a Flox developer environment. Let&#8217;s use Pandas within our container to prove it:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z732!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z732!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 424w, https://substackcdn.com/image/fetch/$s_!z732!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 848w, https://substackcdn.com/image/fetch/$s_!z732!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 1272w, https://substackcdn.com/image/fetch/$s_!z732!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z732!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png" width="1456" height="305" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:305,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102631,&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_!z732!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 424w, https://substackcdn.com/image/fetch/$s_!z732!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 848w, https://substackcdn.com/image/fetch/$s_!z732!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 1272w, https://substackcdn.com/image/fetch/$s_!z732!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d438078-4d8c-4ce2-9420-8e20d8075377_1974x414.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>For those unfamiliar with Python / Pandas, the code isn&#8217;t important. Just know that I&#8217;m using Pandas (the `import pandas as pd` snippet) and it&#8217;s running successfully within my shell (i.e. I&#8217;m not running into an error message). If I run this code outside of my container, it&#8217;d fail.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">If you&#8217;ve learned a bit, I&#8217;d love it if you&#8217;d subscribe. Ok, back to the primer below.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>So, if much like Flox / Nix, containers are language and platform agnostic developer environments, then what&#8217;s the catch? Well, like most technologies, containers come with trade-offs. We need to understand <em>exactly </em>how containers are &#8220;isolated&#8221;, and how they achieve this isolation, in order to appreciate their limitations.</p><p>Ok, <em>commen&#231;ons</em>. People have a tendency to overcomplicate containers, but at a high-level, you can just think of a container as a &#8220;slice&#8221; or &#8220;partition&#8221; of your overall machine. Each container has it&#8217;s own: </p><ul><li><p>Resource Limits: a slice of CPU, memory, and I/O resources. This ensures that a container does not over-consume resources and affect other containers or the host system.</p></li><li><p>Network Interfaces: a unique &#8220;address&#8221; within the overall system. This ensures that other containers running on the same machine can&#8217;t access any inbound/outbound traffic.</p></li><li><p>File System: everything needed to run a specific application, such as code, runtime, system tools, and libraries. This ensures that other containers running on the same machine can&#8217;t access my code etc (which is likely proprietary).</p></li><li><p>Etc.</p></li></ul><p>Where folk often get tripped-up is on the difference between containers and &#8220;virtual machines&#8221; (or &#8220;VMs&#8221;). Put very simply, the ~one resource containers do share is the host machine&#8217;s underlying operating system. VMs are greedy, they want a copy of the operating system (a &#8220;guest OS&#8221;) and all.</p><p>Containers achieve this isolation by using two Linux kernel (note: Linux, not other OS&#8217;s) utilities: <a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/resource_management_guide/ch01">Control Groups</a> (or &#8220;cgroups&#8221;) and <a href="https://man7.org/linux/man-pages/man7/namespaces.7.html">Namespaces</a>. Alas, this is where our trade-offs begin (particularly when working with macOS / Windows).</p><p>Firstly, when using macOS or Windows (<a href="https://www.patentlyapple.com/2023/03/apples-macos-has-been-steadily-gaining-ground-on-microsofts-windows-for-more-than-a-decade-and-the-stats-dont-really-tell.html">80%+ of desktops</a>), I, naturally, can&#8217;t access Linux-native utilities like cgroups or namespaces. So, when working with containers, Docker actually first spins up a Linux virtual machine, <em>and theeen</em>, we access cgroups and namespaces to create a container. Rather circuitous, non? </p><p>This is one of the reasons why we have to install Docker Desktop when working with macOS. Docker Desktop does a lot of heavy-lifting to make containers work across all machines. Again, there&#8217;s no such requirement for Flox / Nix.</p><p>I can get over this <a href="https://www.techopedia.com/definition/32239/virtualization-tax#:~:text=Virtualization%20tax%20refers%20to%20the,as%20opposed%20to%20physical%20equipment.">&#8220;virtualisation tax&#8221;</a>. What I can&#8217;t get comfortable with is that containers&#8217; strong isolation properties actually impede us from accelerating AI workloads via GPUs (amongst many other impediments). In order to begin to work with GPUs we need Nvidia&#8217;s <a href="https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html">Container Toolkit</a>, which itself requires some config.</p><p>Whereas, as you may recall, when using Flox (<a href="https://flox.dev/blog/flaim">FLAIM</a>) earlier we had no problem using our GPU to accelerate Stable Diffusion. We used Flox in <em>exactly</em> the same manner as if we we running &#8220;traditional&#8221; software. <em>This is how habits are formed.</em> </p><p>So, to sum up, Flox is a language and platform agnostic developer environment and package manager. Whilst it rhymes with Docker, Flox doesn&#8217;t incur Docker&#8217;s virtualisation tax, it can seamlessly access system resources and it&#8217;s, frankly, a better developer experience. These properties are why Nix is often referred to as &#8220;containers without containers&#8221;. Or perhaps, containers, without Docker &#128521; (I jest, <a href="https://flox.dev/blog/flox-and-containers">they play nice</a>).</p><p>What&#8217;s kinda incredible about Flox / Nix is that we haven&#8217;t really scratched the surface re. why Flox / Nix&#8217;s developer environments, builds, packages, etc., are <em>objectively </em>more reproducible (reducing performance/security issues) than Docker&#8217;s / containers also. Thankfully for you all, I&#8217;ve scratched this surface previously with a <a href="https://whynowtech.substack.com/p/nix">primer on Nix</a>.</p><div><hr></div><p>Ok, this primer is wrapping up. At this point, I want to be clear that whilst this post may have seemed &#8220;anti-Docker&#8221;, this is by no means the case. I have used Docker for most of my &#8220;professional&#8221; life, and will continue to do so for the use cases it&#8217;s suited to best. </p><p>If anything, the fact that Docker has been used for so much beyond its core use case (running cloud apps in production) is a testament to its technology and community. One of the perks of investing in infra is that it&#8217;s versatile. Just ask the <a href="https://whynowtech.substack.com/p/restate-and-durable-execution#:~:text=I%20recently%20spent%20some%20time%20trawling%20through%20the%20history%20of%20The%20Dow%20Chemical%20Company%20with%20some%20friends.%20Niche%20crew%2C%20yes.%20The%20winters%20are%20cold%20in%20London.">Dow Chemical Company</a>!</p><p>So, my final ask to you all is to unite these two worlds. 1) <a href="https://flox.dev/docs/">Give Flox a go</a> if you haven&#8217;t already and 2) build a Docker image with FloxBuild (ready soon &#128064;).    </p><p>Oh yeah, and subscribe etc if you enjoyed this and/or learned a thing or two. If you want to say hi, I&#8217;m at alex@tapestry.vc</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Why Now! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Tracebit: Going From the “Top 1%” to 100%]]></title><description><![CDATA[Announcing our Investment in Tracebit's $5M Seed Round]]></description><link>https://whynowtech.substack.com/p/tracebit-going-from-the-top-1-to</link><guid isPermaLink="false">https://whynowtech.substack.com/p/tracebit-going-from-the-top-1-to</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Tue, 09 Jul 2024 09:45:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d16d13f9-977a-4eb8-a5b2-f6dffeed03d7_1556x1556.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>A year since our first meeting, we&#8217;re delighted to announce <a href="https://www.tapestry.vc/">Tapestry VC&#8217;s</a> investment in <a href="https://tracebit.com/">Tracebit&#8217;s</a> $5M Seed round alongside Accel and industry luminaries like Mandy Andress (CISO, Elastic), Josh Yavor (CISO, Tessian) and Guy Podjarny (Founder, Snyk).</em></p><p><em>Tracebit has now deployed close to 2,000 canaries across hundreds of production accounts including those of Riot Games, Docker and Synthesia. A few basis points closer to &#8220;100%&#8221;. </em></p><p><em><strong>Read the announcement from Andy at Tracebit <a href="https://www.linkedin.com/posts/andy-m-smith_tracebit-announces-5m-fundraise-to-bring-activity-7216358971501068288-0gYs?utm_source=share&amp;utm_medium=member_desktop">here</a> and take a glimpse into their research <a href="https://tracebit.com/blog">here</a>.</strong></em><strong> </strong></p><p><em>Congratulations Andy, Sam and the Tracebit team!</em>&nbsp;</p><div><hr></div><p>Why canaries &amp; what are they? There was once a time when security teams could plausibly focus solely on &#8220;prevention&#8221; (e.g. stop that employee from clicking that phishing email). However:</p><ol><li><p>The stack of technology upon which an organisation is built has become far too complex (hello, <a href="https://whynowtech.substack.com/p/restate-and-durable-execution">durable execution</a>) and ephemeral (looking at you, <a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html#:~:text=The%20Lambda%20service%20runs%20your%20function%20only%20when%20needed%20and%20scales%20automatically.">lambdas</a>) to properly reason about whether it&#8217;s consistently &#8220;secure&#8221;.</p></li><li><p>Whilst detection engineering is important, if a false positive is a &#8220;one in a million event&#8221; but there are <a href="https://blog.zomato.com/building-a-cost-effective-logging-platform-using-clickhouse-for-petabyte-scale#:~:text=With%20a%20maximum%20production%20rate%20of%20150%20million%20logs%20per%20minute%2C%20this%20leads%20to%20the%20production%20of%20over%2050%20TB%20of%20uncompressed%20logs%20per%20day.%C2%A0">billions of events</a>, then there&#8217;ll actually be a decent number of false positives.</p></li><li><p>The number of security breaches published publicly tells a compelling story that even the best-resourced security teams (<a href="https://techcrunch.com/2023/11/29/okta-admits-hackers-accessed-data-on-all-customers-during-recent-breach/">Okta</a>, <a href="https://www.wired.com/story/snowflake-breach-advanced-auto-parts-lendingtree/">Snowflake</a>, <a href="https://www.threatdown.com/blog/mongodb-warns-customers-about-data-breach-after-cyberattack/">MongoDB</a>) can and will be compromised.</p></li></ol><p>Canaries flip this problem on its head by <a href="https://www.darkreading.com/vulnerabilities-threats/after-the-uber-breach-3-questions-all-cisos-should-ask-themselves-#:~:text=As%20the%20CISO%20for%20a%20security%20vendor%2C%20I%20know%20all%20too%20well%20the%20motivation%20and%20determination%20of%20bad%20actors%20and%20nation%20states.%20I%20also%20understand%20the%20odds%20organizations%20face%20in%20falling%20victim%20to%20an%20attack%20%E2%80%94%20organizations%20must%20assume%20they%27ll%20be%20breached.%20What%20will%20you%20do%20when%20that%20happens%3F">&#8220;assuming breach&#8221;</a>. Instead of preventing and/or hunting for the one in a million <em>event</em> that &#8220;shouldn&#8217;t happen&#8221; they instead, create a <em>resource</em> that shouldn&#8217;t be interacted with.</p><p>Because this resource is wholly created and owned by the person looking to do the detection, they can fully reason about what interactions with it are acceptable and significantly reduce the possibility of misleading false positives creeping in. Same same, but different.</p><div><hr></div><p>Why now? When we first studied canaries and other deception technologies two years ago we noticed something that piques our interest at Tapestry &#8212; dogma. During this time, we were hastily told that <em>&#8220;canaries are only for the top 1%&#8221;</em> or, a personal favourite, <em>&#8220;Atlassian <a href="https://www.youtube.com/watch?v=sK1vYPbXtfc">can scale</a> a deception program, but you can&#8217;t&#8221;</em>.</p><p>The convenient thing about dogma is that it can break down rather quickly if you just ask &#8220;why&#8221; a few times. Answers included: alert imprecision, cumbersome maintenance, untenable costs, et cetera. All seemingly fair points. </p><p>However, during our explorations, a duo of founders (who previously helped take Tessian from <a href="https://www.tessian.com/blog/proofpoint-announces-intent-to-acquire-tessian/">seed to exit</a>) noted that these points are somewhat moot when applied to modern cloud environments. They believed that canaries could go from the top 1% to 100%.</p><p>The team has since <a href="https://tracebit.com/blog/canary-infra-bringing-honeypots-towards-general-adoption">jotted down</a> why the modern cloud is a fundamental unlock:&nbsp;</p><ol><li><p><strong>Alert Precision:</strong> any interactions with these resources produce a <a href="https://gist.github.com/alexmackenzie-wx/e9940124da3b6ddb60c53db8cea344bb">very rich</a> audit trail (in AWS it's CloudTrail) that doesn't just provide an IP address but also session, user, role, user agent and more, making it much more actionable.</p></li><li><p><strong>Maintenance</strong>: AWS is responsible for operating systems and software patches of these resources, most are completely transparent to us (e.g. when Log4Shell happened - Amazon paged their engineering team, not their customers).</p></li><li><p><strong>Cost</strong>: These resources are usage based, so either very cost effective (cents a month) or free to deploy.</p></li></ol><div><hr></div><p>Rarely in cybersecurity do you find a category with so much &#8220;space&#8221; (thank you, dogma). This admittedly made us apprehensive, but fortunately, we had no shortage of material to keep us busy: Andy has been writing about canaries <a href="https://andrewmichaelsmith.com/2010/10/honeypot-hosting/">since 2010</a>, deception jobs were <a href="https://gamejobs.co/Staff-Security-Engineer-Information-Security-Deception-Technology-at-Riot-Games">cropping up</a> and <a href="https://nsarchive.gwu.edu/sites/default/files/documents/rmsj3h-751x3/2022-11-29-arXiv-Sludge-for-Good-Slowing-and-Imposing-Costs-on-Cyber-Attackers-Cornell%20Tech.pdf">&#8220;sludge for good&#8221;</a> was making the rounds in various forums.</p><p>Our intrigue grew into conviction as we spent the year getting to know <a href="https://www.linkedin.com/in/andy-m-smith?miniProfileUrn=urn%3Ali%3Afs_miniProfile%3AACoAAC3eNrkBQ5WM_8vlVIk5pHx5rZPkO6Y-Gls&amp;lipi=urn%3Ali%3Apage%3Ad_flagship3_search_srp_all%3BzTw1%2BqlhR5%2Bs2qO6fEtOmQ%3D%3D">Andy</a>, <a href="https://www.linkedin.com/in/sam-j-cox?miniProfileUrn=urn%3Ali%3Afs_miniProfile%3AACoAABG4zecBc2mz1ZKKaiwDlfyIFRkQ88j7juU&amp;lipi=urn%3Ali%3Apage%3Ad_flagship3_search_srp_all%3Bow%2F73bHqSpC7vo%2BE1TSxqw%3D%3D">Sam</a> and <a href="https://tracebit.com/">Tracebit</a>. Security Engineers raved about their chats with Tracebit; new product pillars (like <a href="https://tracebit.com/blog/canary-infra-bringing-honeypots-towards-general-adoption">canary infra</a>) were rolled out at a rapid clip; and <a href="https://tracebit.com/blog/how-to-find-the-aws-account-id-of-any-s3-bucket">Sam&#8217;s research</a> hit the top spot on Hacker News. </p><p>This was clearly a product for security engineers, built by security engineers. We couldn&#8217;t think of a better pairing and team to bring canaries to &#8220;the rest of us&#8221;.</p><div><hr></div><p>Thank you once again Andy &amp; Sam for having us at <a href="https://www.tapestry.vc/">Tapestry VC</a> on this journey with you. </p><p></p>]]></content:encoded></item><item><title><![CDATA[Restate & Durable Execution]]></title><description><![CDATA[Life could do with a little more async/await.]]></description><link>https://whynowtech.substack.com/p/restate-and-durable-execution</link><guid isPermaLink="false">https://whynowtech.substack.com/p/restate-and-durable-execution</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Tue, 06 Feb 2024 17:36:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4dd73994-b73c-49d1-ad6c-1f156e8b1edc_228x189.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>If you enjoy these primers, I&#8217;d appreciate it if you favourite this post&#8217;s <a href="https://twitter.com/alex__mackenzie">tweet</a> or <a href="https://www.linkedin.com/in/alex-mackenzie-6aa80ab4/recent-activity/all/">LinkedIn post</a> to help spread the good (?) word of Why Now!</em></p><p><em>I&#8217;m at alex@tapestry.vc should you ever wish to chat, always up for saying hello.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I6Kg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I6Kg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png 424w, https://substackcdn.com/image/fetch/$s_!I6Kg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png 848w, https://substackcdn.com/image/fetch/$s_!I6Kg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png 1272w, https://substackcdn.com/image/fetch/$s_!I6Kg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I6Kg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png" width="892" height="252" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:252,&quot;width&quot;:892,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;divider&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="divider" title="divider" srcset="https://substackcdn.com/image/fetch/$s_!I6Kg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png 424w, https://substackcdn.com/image/fetch/$s_!I6Kg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png 848w, https://substackcdn.com/image/fetch/$s_!I6Kg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.png 1272w, https://substackcdn.com/image/fetch/$s_!I6Kg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fced15c71-a6e5-4e74-b3c3-238dd1783170_892x252.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>I recently spent some time trawling through the history of <a href="https://www.dow.com/">The Dow Chemical Company</a> with some friends. Niche crew, yes. The winters are cold in London.</p><p>If you think <a href="https://whynowtech.substack.com/p/nix">Nix</a> or <a href="https://whynowtech.substack.com/p/webgpu">WebGPU</a> are complicated, try getting your noggin&#8217; around the production of bromine in 1897! A humbling experience. </p><p>Safe to say that I left this excursion with a bruised ego, but many lessons: Dow was basically a <a href="https://www.invent.org/inductees/otis-ray-mcintire#:~:text=Ray%20McIntire%20invented%20polystyrene%20foam,wind%2C%20rain%2C%20and%20moisture.">&#8220;publisher&#8221;</a>, it&#8217;s the &#8220;chemical company&#8217;s, chemical company&#8221;, and they spend a tonne more time dissecting price pressure in their <a href="https://s23.q4cdn.com/981382065/files/doc_financials/2023/q4/4Q23_Dow_Earnings_Presentation.pdf">quarterly results</a> than.. MongoDB.</p><p>The lesson that stood out though was that: <em>product &#8220;atomicity&#8221; leads to company durability</em>. One of Dow&#8217;s first products was bromine (silver bromide specifically), a light-sensitive compound that was used for development in analog photography. </p><p>This development process changed from the 1970s onwards with digital photography; <a href="https://www.theatlantic.com/business/archive/2012/01/kodak-files-bankruptcy/332934/#:~:text=Despite%20developing%20many,year%20since%202004.">a calamity</a> for film-based juggernauts like Kodak, yet Dow, rather deftly, siphoned its bromine assets towards other use cases: flame retardants, tear gas, pharmaceuticals, etc. </p><p>Turns out that when the product you produce is literally an element on the periodic table, it tends to be rather versatile. It&#8217;s no secret that &#8220;platforms&#8221; are attractive for this reason: oh you like vectors? Great, check out our <a href="https://www.mongodb.com/blog/post/dedicated-search-nodes-vector-search-now-in-general-availability?tck=pencil_banner_hp">Atlas Vector Search</a> product. Think stream processing is de rigueur? <a href="https://www.mongodb.com/products/platform/atlas-stream-processing">Atlas Stream Processing</a> does that. </p><p>This said, Dow gave me a deeper appreciation of what it means to be a true platform. As I wrote this primer on <a href="https://restate.dev/">Restate</a>, I saw a similar opportunity. </p><p>The reason why it&#8217;s kinda difficult to understand (&amp; hence, &#8220;in need&#8221; of a primer) is that it&#8217;s atomic. Want Lambdas represented as code? <a href="https://www.restate.dev/blog/suspendable-functions-make-lambda-the-perfect-application-platform/">We gotcha</a>. Need consistent multi-writes? We can do <a href="https://restate.dev/#:~:text=Consistent%20dual%2D/multi%20writes">that too</a>. It&#8217;s difficult to think of Restate as one thing, because it is in fact, everything. Let&#8217;s dig in.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"> Subscribe for primers durably delivered to your inbox</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Restate is an <strong>event broker &#8220;</strong>on steroids&#8221;<strong>.</strong> It:</p><ul><li><p>Routes messages/invocations. </p></li><li><p>Tracks message/invocation execution. </p></li><li><p>Handles retries and recovery via persisting partial progress. </p></li></ul><p>There&#8217;s a lot here, I know. We&#8217;ll break it up piece-by-piece.</p><div><hr></div><p><strong>Section 1 - Event Broker</strong></p><p>Events are something that happen (e.g. a customer payment) at a point in time (e.g. 2023-01-15-14:30). Surprised? These events are represented as &#8220;logs&#8221; and collected and processed (enriched, normalised, et cetera) by titans like <span class="cashtag-wrap" data-attrs="{&quot;symbol&quot;:&quot;$DDOG&quot;}" data-component-name="CashtagToDOM"></span>,  <span class="cashtag-wrap" data-attrs="{&quot;symbol&quot;:&quot;$ESTC&quot;}" data-component-name="CashtagToDOM"></span> (via Elastic Beats or Logstash) and <span class="cashtag-wrap" data-attrs="{&quot;symbol&quot;:&quot;$CFLT&quot;}" data-component-name="CashtagToDOM"></span>.</p><p>Here&#8217;s a very simple log below. When these logs are sent somewhere they&#8217;re often called &#8220;messages&#8221;. At first glance, they may look a little intimidating, but study their contents and you&#8217;ll find they&#8217;re really quite intuitive.</p><pre><code>{
  "event_type": "payment_intent.succeeded",
  "created_at": "2023-01-15T14:30:00Z",
  "data": {
    "object": "payment_intent",
    "amount": 2500,
    "currency": "USD",
    "status": "succeeded",
    }
  }  </code></pre><p>It&#8217;s tr&#232;s important to internalise that, we collect a <a href="https://whynowtech.substack.com/p/malloy-data#:~:text=With%20what%20we%20know%20now%20(recall%2C%20%E2%80%9Caccidents%20of%20history%E2%80%9D)%2C%20it%E2%80%99s%20clear%20that%20this%20is%20an%20incredibly%20rigid%2C%20and%20rather%20abstruse%20data%20model%20to%20grok%20at%20scale.%20Imagine%20attempting%20to%20parse%20Zomato%E2%80%99s%20150M%20logs%20p/m%20if%20represented%20this%20way%20(!).">shit-tonne</a> (industry measure) of logs. Why? Well, we can put &#8216;em to work. This is the vocation of the event broker.  </p><p>Brokers do this by organising these events into &#8220;topics&#8221; (think of them as folders stored on the broker). Par example, we could create a &#8220;payment_events&#8221; topic that records Stripe payments like the one above. Each time a new payment is made, the resulting log is sent to the topic:</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_!TI2Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TI2Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png 424w, https://substackcdn.com/image/fetch/$s_!TI2Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png 848w, https://substackcdn.com/image/fetch/$s_!TI2Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png 1272w, https://substackcdn.com/image/fetch/$s_!TI2Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TI2Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png" width="1156" height="428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:428,&quot;width&quot;:1156,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35082,&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_!TI2Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png 424w, https://substackcdn.com/image/fetch/$s_!TI2Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png 848w, https://substackcdn.com/image/fetch/$s_!TI2Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.png 1272w, https://substackcdn.com/image/fetch/$s_!TI2Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3a082c1-cbb6-4940-a4a1-0a6495ce9af3_1156x428.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>These events aren&#8217;t providing utility yet though, are they? They&#8217;re in need of a destination (or &#8220;sink&#8221;) that consumes them. In our payments example, the sink could be a dashboard that lists new sales in real time.</p><p>What&#8217;s cool, I guess, is that brokers can also route logs from topic-to-topic. An event broker like <a href="https://www.confluent.io/">Confluent</a> (<a href="https://www.confluent.io/en-gb/what-is-apache-kafka/">Kafka</a>), may send each new log to a processing engine (i.e. software that transforms the log) like <a href="https://flink.apache.org/">Flink</a>, and then route the computed result to another topic. </p><p>Allow me to illustrate the above. Notice that the &#8220;payment_events&#8221; log includes a sales price (called &#8220;amount&#8221; in our log)? Each time a new log enters &#8220;payment_events&#8221;, we could send it to Flink to recalculate the median sales price of <em>all of the logs </em>it&#8217;s processed. We&#8217;d then send this data to the &#8220;median_sales_price&#8221; topic. Get it now?</p><p>My walkthrough hasn&#8217;t quite done the thankless role of an event broker justice however. <em>Distributed systems are hard</em>. What if an event fails to deliver (known as a &#8220;dead letter&#8221;) due to network issues? Or perhaps, a &#8220;sink&#8221; is overwhelmed by the deluge of `item_added_to_cart` events it&#8217;s receiving on Cyber Monday? <em>Told ya</em>.</p><p>I&#8217;ve adorned Confluent&#8217;s Kafka with it&#8217;s very own `whynow_cluser` which I think best illustrates how much these event brokers do. Replication (for data resiliency), data retention (for compliance), event flushing (for performance), it&#8217;s all there:  </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GZg9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GZg9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png 424w, https://substackcdn.com/image/fetch/$s_!GZg9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png 848w, https://substackcdn.com/image/fetch/$s_!GZg9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png 1272w, https://substackcdn.com/image/fetch/$s_!GZg9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GZg9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png" width="498" height="461" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:461,&quot;width&quot;:498,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59734,&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_!GZg9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png 424w, https://substackcdn.com/image/fetch/$s_!GZg9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png 848w, https://substackcdn.com/image/fetch/$s_!GZg9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.png 1272w, https://substackcdn.com/image/fetch/$s_!GZg9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7271c82b-fc72-4874-baf6-7aeca6cb4964_498x461.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>Quite a bit there, huh? In fact, event brokers are so complex, that <a href="https://www.conduktor.io/">companies</a> can build nice businesses (<a href="https://www.conduktor.io/#:~:text=Trusted%20by%20more%20than%2015%2C000%20companies%20worldwide">15,000 customers</a>) providing better Kafka UIs<em>, </em>for Confluent&#8217;s Kafka UI. You don&#8217;t see myopia like this in PaaS too often! </p><p>Cool. You&#8217;ve hopefully learned what an event broker (&amp; Kafka) is in ~480 words. If true, I&#8217;m <a href="https://www.youtube.com/watch?v=06iRM1Ghr1k">kinda proud of that</a>. So where does Restate add the, eh.. steroids?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"> {event_type: subscribe pls?}</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><strong>Section 2 - RPC</strong></p><p>So far, we&#8217;ve only discussed how event brokers like Kafka transport &#8220;messages&#8221; (remember, event logs). However, what if they could also transport &#8220;procedures&#8221;?</p><p>Well, recall that our Restate description also mentioned &#8220;invocations&#8221;. An invocation is when a function (i.e. procedure) is &#8220;called&#8221; like so:  </p><pre><code># Define a Python function
def greet(title):
    return "Hello, {title}!"

# Invoke the function
greet("Why Now reader")</code></pre><p>In <a href="https://aws.amazon.com/microservices/">microservice architectures</a>, it&#8217;s common to have a number of these functions all residing in their own servers, waiting to be called-upon. For example, a user-facing application (think a checkout screen) might call, or &#8220;invoke&#8221; a microservice (like a KYC check).</p><p>Whilst there are many ways to invoke a function remotely, this &#8220;invoking&#8221; is often done through the RPC (Remote Procedure Call) protocol.</p><p>Before we delve into RPC though, let&#8217;s first look at an alternative; partially because it&#8217;s Sunday evening and re-learning RPC requires work, but mostly because doing so will serve as a helpful contrast.   </p><p>Whilst I&#8217;m not prepared to get you the data (again, Sunday), I&#8217;m willing to make a bet that plain ole HTTP requests are the most common way to invoke functions remotely (i.e. from a &#8220;client&#8221; like your web browser). </p><p>Thus, many, people write web servers that.. serve.. these HTTP requests like so:  </p><pre><code>from flask import Flask

app = Flask(__name__)

@app.route('/example', methods=['GET'])
def example_route():

    return 'This is the response from the example route.'

if __name__ == '__main__':
    app.run(debug=True)</code></pre><p>Looks complicated, eh! Most of this is &#8220;boiler plate&#8221; stuff so don&#8217;t fret. All that really matters is this:</p><pre><code>@app.route('/example', methods=['GET'])
def example_route():

    return 'This is the response from the example route.'</code></pre><p>Here we&#8217;re saying, when the url <em>whynow.onrender.com/example</em><strong> </strong>receives a HTTP GET request, invoke the function &#8220;example_route&#8221;.<strong> </strong></p><p>Hopefully it&#8217;s clear that we now have a way to invoke a function remotely, all we need to do is make a HTTP GET request. Great, how does one do wanna them?</p><p>Well, making GET requests is quite easy, as all you gotta do is visit (i.e. GET) the <a href="https://whynow.onrender.com/example">URL</a>. Let&#8217;s do something a little more fun though. Mac users, press command + spacebar. Windows users, <a href="https://www.computerworld.com/article/3676596/how-to-manage-and-customize-windows-terminal.html">do better</a>? Now, search for your &#8220;terminal&#8221; and open it. </p><p>Ok, now type: <em>curl whynow.onrender.com/example </em>in that fine terminal of yours. Et voil&#224;! You&#8217;ve made a HTTP request. What&#8217;s up, h@ck&#583;r.</p><div><hr></div><p>The thing is, like most general-purpose technologies, HTTP isn&#8217;t optimised for making function calls. RPC on the other hand, is. </p><p>RPC intends to make function calls appear &#8220;local&#8221;. Its goal is to make function calls look as though they&#8217;re made directly in a single file; when in reality, you&#8217;re calling functions that live in many different files, on many different servers (aka &#8220;microservices&#8221;).  </p><p>Why? Well, think about it. It&#8217;s much easier to reason about functions that are &#8220;native&#8221; to the file (e.g. app.js) you&#8217;re working on. Local functions don&#8217;t need any superfluous information about handling network protocols. They&#8217;re local! There&#8217;s no need for a network to transport any data to a remote function.  </p><p>Let&#8217;s make this point really hit <em>/home</em>. Take a look at what our app.js file (running in our browser &#8220;client&#8221;) could look like when plain ole HTTP is involved. It&#8217;s ok, your head is supposed to hurt:  </p><pre><code>const http = require('http');

// Define the server's address
const hostname = 'whynow.onrender.com';
const port = 8000;
const path = '/example';

// Create an HTTP request options object
const options = {
    hostname: hostname,
    port: port,
    path: path,
    method: 'GET',
};

// Create an HTTP request
const req = http.request(options, (res) =&gt; {
    let data = '';

    // Receive data from the server
    res.on('data', (chunk) =&gt; {
        data += chunk;
    });

    // Process the server's response
    res.on('end', () =&gt; {
        if (res.statusCode === 200) {
            console.log('Data received from server:');
            console.log(data);
        } else {
            console.error('Error:', res.statusCode);
        }
    });
});

// Send the HTTP GET request to the server
req.end();</code></pre><p>There&#8217;s a lot of cruft here that makes it clear that you are, in fact, not making a local function call. Perhaps it&#8217;s also now clear why we need a better way? </p><p>In RPC we use &#8220;stubs&#8221; and &#8220;skeletons&#8221; to abstract network communication details (the cruft above). Stubs are used on the client-side and look like so:</p><pre><code>// xmlrpc is just a "library" that makes using RPC easier
const xmlrpc = require('xmlrpc'); 

// Create an RPC client (your "stub")
const client = xmlrpc.createClient({ host: 'whynow.onrender.com', port: 80, path: '/example' });

// Define the remote procedure and its parameters
const methodName = 'add';
const params = [3, 4];

client.methodCall(methodName, params, (error, value) =&gt; {
    console.log('Result:', value);
});</code></pre><p>Again, don&#8217;t get bogged down on the code above. All you need to appreciate is that the &#8220;add&#8221; function actually lives on another file (<em>http://whynow.onrender.com/example</em>.)  </p><p>It looks kind of &#8220;local&#8221; though, right? It&#8217;s as if we&#8217;ve just imported the &#8220;add&#8221; function as if it was a library like xmlrpc. Note that there&#8217;s also no mention of what HTTP &#8220;method&#8221; (i.e. GET) we&#8217;re availing of, status codes, or anything that suggests that we&#8217;re making a request over a network. Nice.</p><p>Before I get called out by &#8220;astute&#8221; (&#128521;) readers, much like RPC, I have abstracted things a little here. For those that wish to go deeper, look into RPC skeletons, interface definitions and protocol buffers (<a href="https://buf.build/">Buf</a> is cool). </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Support your &#8220;local&#8221; Substack author?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><strong>Section 3 - Durable Execution</strong></p><p>Ok, we&#8217;re kinda on a roll here. You now know what an &#8220;event broker&#8221; is, what &#8220;messages&#8221; and &#8220;invocations&#8221; are, and I&#8217;ve endowed you with a new acronym to <em>woo </em>folk with at dinner parties. Let&#8217;s begin to tie this all together. </p><p>Let&#8217;s revisit our definition: Restate is an <strong><s>event broker</s></strong> that routes and tracks both <strong><s>messages</s></strong> and <strong><s>invocations</s></strong>. It also handles <strong>retries</strong> and <strong>recovery</strong> via <strong>persisting partial progress</strong>.   </p><p>Astute readers (the good kind &#128521;) might have already guessed what retries are. As we learned through studying Kafka, messages and invocations may fail for a shit-tonne (again, industry metric) of reasons. <em>Distributed systems are hard</em>.  </p><p>It&#8217;s commonplace for developers to write logic that handles when things go awry. For example, in frontend development, it&#8217;s common to use `try` and `catch` blocks to handle network errors: </p><p>A frontend developer might `try` to fetch some data from a remote database (i.e. a network request is made), and if an error occurs, `catch` it and run some alternative logic in response. Sometimes this alternative logic is simply, trying again after a period of time has elapsed (a &#8220;retry&#8221;).</p><p>The above is a rather rudimentary example though. In reality, a single RPC call may trigger a plethora of functions across a series of microservices. One big game of distributed dominos. </p><p>Let&#8217;s look at a system that&#8217;s a little more complex, shall we? Imagine a world where I sell Why Now dad caps. When an order is placed, my system needs to: </p><ul><li><p>Deduct inventory </p></li><li><p>Charge the customer's credit card </p></li><li><p>Send a confirmation email</p></li></ul><p>This involves several remote services (perhaps called via RPC) and potential points of failure. For example, what if everything&#8217;s rosy for my inventory service, but a customer&#8217;s credit card on file has expired? </p><p>In this instance, I may have deducted my inventory count, despite an incomplete sale. <em>C'est ne pas bon</em>. To address this potential issue, I could send an error &#8220;message&#8221; (remember, a log) to an &#8220;event broker&#8221; like <a href="https://restate.dev/">Restate</a>, <a href="https://temporal.io/">Temporal</a>, <a href="https://www.inngest.com/">Inngest</a>, <a href="https://www.resonatehq.io/">Resonate</a>, etc., if a payment ever fails.</p><p>For this specific error, we might end the current workflow and &#8220;rollback&#8221; our inventory to its former state. Through our error message, we could then trigger a customer email informing them that they need to update their payment method. Notice how we&#8217;ve made our application more resilient, or, <em>durable</em>?    </p><p>Event brokers that are predominately used to increase the durability of our distributed systems (again, <a href="https://restate.dev/">Restate</a>, <a href="https://temporal.io/">Temporal</a>, <a href="https://www.inngest.com/">Inngest</a>, <a href="https://www.resonatehq.io/">Resonate</a>) are known as &#8220;durable compute&#8221; or &#8220;durable execution&#8221; providers. </p><p>Their focus is slightly different to event brokers like <a href="https://www.confluent.io/">Confluent</a> and <a href="https://redpanda.com/">Redpanda</a> whose primary function is real-time data transport. As a result, durable compute providers come fully-loaded with numerous helpful utilities like: retries, error handlers, timeouts, state maintenance, etc.  </p><p>Cool, you&#8217;ve got <s>retries</s> down. Sometimes you want to pick-up where you left things off though, you want to &#8220;recover&#8221; a workflow. </p><p>In this case, perhaps we decide to keep our inventory count deducted for a period of time (i.e. we persist the &#8220;state&#8221; of our workflow). We&#8217;ll still send an email to the customer asking them to update their payment method, and, if they do so hastily, we can just resume our workflow from where it left off (known as &#8220;workflow continuation&#8221;). </p><p>Cool, that&#8217;s <strong><s>recovery</s></strong> and <strong><s>persisting partial progress</s></strong> down too. Want a dad cap?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Re-try subscribing?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><strong>Section 4 - Restate</strong></p><p>Ok so: Restate is an <strong><s>event broker</s></strong> that routes and tracks both <strong><s>messages</s></strong> and <strong><s>invocations</s></strong>. It also handles <strong><s>retries</s></strong> and <strong><s>recovery</s></strong> via <strong><s>persisting partial progress</s></strong>.   </p><p>Let&#8217;s delve into <a href="https://restate.dev/">Restate</a> itself now and how it actually achieves all of the above. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SkFf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SkFf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png 424w, https://substackcdn.com/image/fetch/$s_!SkFf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png 848w, https://substackcdn.com/image/fetch/$s_!SkFf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png 1272w, https://substackcdn.com/image/fetch/$s_!SkFf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SkFf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png" width="1305" height="632" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:632,&quot;width&quot;:1305,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:162128,&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_!SkFf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png 424w, https://substackcdn.com/image/fetch/$s_!SkFf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png 848w, https://substackcdn.com/image/fetch/$s_!SkFf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.png 1272w, https://substackcdn.com/image/fetch/$s_!SkFf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88026749-746b-4a02-82a6-9f05a1c0b461_1305x632.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>The image on the right is just a microservices architecture. Don&#8217;t worry about it, but note familiar terms like RPC, durable execution and retries? Nice. You&#8217;ll recognise most of the terms on the left, the one that might throw you is &#8220;async/await&#8221;.  </p><p>Async/await is a common pair of keywords used in web development. In JavaScript, you place &#8220;async&#8221; in front of a function definition like so:  </p><pre><code><strong>async</strong> function fetchData() {
  try {
    const response = await fetch('https://example.com/api/data');
    const data = <strong>await</strong> response.json();
    console.log(data);
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

fetchData();

// subsequent code blocks:
const numbers = [1, 2, 3, 4, 5];

// Use the map function to square each number
const squaredNumbers = numbers.map((num) =&gt; num * num);

// Print the squared numbers to the console
console.log("Squared numbers:", squaredNumbers);</code></pre><p>All async/await does here is enable a developer to request (often called &#8220;fetch&#8221; in web dev) some remote data, without impeding the execution of subsequent code blocks. </p><p>We&#8217;ve already learned why this matters, requesting data over networks can be unreliable. The last thing we want on our website is for the page not to fully render (i.e. subsequent code not execute) due to network issues. Async/await solves 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_!Zjzx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Zjzx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 424w, https://substackcdn.com/image/fetch/$s_!Zjzx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 848w, https://substackcdn.com/image/fetch/$s_!Zjzx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 1272w, https://substackcdn.com/image/fetch/$s_!Zjzx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Zjzx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png" width="1281" height="682" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:682,&quot;width&quot;:1281,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:141341,&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_!Zjzx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 424w, https://substackcdn.com/image/fetch/$s_!Zjzx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 848w, https://substackcdn.com/image/fetch/$s_!Zjzx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 1272w, https://substackcdn.com/image/fetch/$s_!Zjzx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1de317d8-d049-40ed-bd43-c09407dac1a7_1281x682.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>To be honest, this section threw me for a spin when I first saw it. It&#8217;s actually fine though. It&#8217;s just a use cases section, chill.</p><p><strong>1. Lambda Workflows as Code</strong></p><p>Simply put, <a href="https://docs.aws.amazon.com/lambda/latest/dg/welcome.html">Lambdas</a> are remote servers that execute some code (e.g., our inventory deduction function). Microservice architectures often chain many Lambdas together based on some &#8220;if this, then that&#8221; (i.e. event-driven) logic.</p><p>This &#8220;if this, then that&#8221; logic typically lives in a separate JSON (i.e. configuration file) to the Lambda itself. Note the &#8220;triggers&#8221; and &#8220;events&#8221; in the below JSON file:</p><pre><code>.json

{
  "FunctionName": "MyLambdaFunction",
  "Runtime": "nodejs14.x",
  "Handler": "index.handler",
  "MemorySize": 256,
  "Timeout": 10,
  "Environment": {
    "Variables": {
      "API_KEY": "my-api-key",
      "DATABASE_URL": "https://my-database-url"
    }
  },
  "Role": "arn:aws:iam::123456789012:role/lambda-execution-role",
  "Triggers": [
    {
      "Type": "APIGateway",
      "Source": "MyApiGateway",
      "Method": "POST"
    },
    {
      "Type": "S3",
      "Source": "MyS3Bucket",
      "Events": ["ObjectCreated"]
    }
  ]
}
</code></pre><p>With Restate, this configuration logic is replaced by actual code. </p><p>&#8220;Who cares?&#8221; says the, em.. gentleman.. in the back. Well, code is much more flexible than simple &#8220;key:value&#8221; data structures like JSON (e.g., you can&#8217;t &#8220;loop&#8221; in JSON). </p><p>As a result, Restate can implement more sophisticated logic like: <em>&#8220;reliable timers &amp; schedulers&#8221;</em> and function suspension <a href="https://restate.dev/#:~:text=Via%20the%20journal%2C%20functions%20can%20recover%20partial%20progress%20after%20failures%20or%20actively%20suspend%20when%20waiting">[1]</a><a href="https://docs.restate.dev/tour/#:~:text=When%20services%20take,prior%20to%20suspending.">[2]</a> vs. our lowly key:value file. My friend Jack (hello, Jack) co-authored <a href="https://restate.dev/blog/we-replaced-400-lines-of-stepfunctions-asl-with-40-lines-of-typescript-by-making-lambdas-suspendable/">this</a> post on the Restate blog which further <a href="https://restate.dev/blog/we-replaced-400-lines-of-stepfunctions-asl-with-40-lines-of-typescript-by-making-lambdas-suspendable/#:~:text=tl%3Bdr%3A,runtime%2C%20Restate.">extols</a> the benefits of this approach nicely.    </p><p><strong>2. Transactional RPC Handlers</strong></p><p>This one should be kinda easy to grok. Recall our inventory management microservice that has two &#8220;procedures&#8221; (i.e. functions): &#8220;addInventory( )&#8221; and &#8220;deductInventory( )&#8221;.</p><p>When a client calls &#8220;deductInventory( )&#8221;, this request is initially read by an &#8220;RPC Handler&#8221; that, typically, lives in the same microservice. This RPC handler then routes the request to the exact procedure requested by the client.</p><p>Restate bestows our RPC handlers with transactional guarantees. Transactional systems are those that prioritise data consistency and integrity. For example, my inventory management service <em>better be right</em>, as otherwise, I might charge a customer for dad hats that I no longer have.</p><p>One way that transactional systems are achieved is via the concept of &#8220;atomicity&#8221;. This means that either my entire &#8220;transaction&#8221;: <em>deduct inventory &gt; charge customer&#8217;s card &gt; send confirmation email</em> works, or none of it does and the flow rolls-back accordingly. </p><p>As we learned earlier, Restate can persist transaction state.   <em> </em></p><p><strong>3. Event Processing with Kafka</strong>   </p><p>We&#8217;ve already spent time understanding how event brokers build resiliency into their message transportation (e.g., &#8220;dead letter queues&#8221;). So, let&#8217;s not rehash this too much.</p><p>Basically, Restate sits as a proxy between your event broker (Kafka) and your event consumer. It brings the qualities of durable execution to event transportation.     </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j6IQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j6IQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png 424w, https://substackcdn.com/image/fetch/$s_!j6IQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png 848w, https://substackcdn.com/image/fetch/$s_!j6IQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png 1272w, https://substackcdn.com/image/fetch/$s_!j6IQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j6IQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png" width="1327" height="635" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:635,&quot;width&quot;:1327,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:313315,&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_!j6IQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png 424w, https://substackcdn.com/image/fetch/$s_!j6IQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png 848w, https://substackcdn.com/image/fetch/$s_!j6IQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.png 1272w, https://substackcdn.com/image/fetch/$s_!j6IQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3bb0b785-cc26-4abb-8bdd-46cf0fed97c6_1327x635.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>At this point, you likely understand all of the above? If so, sweet. This stuff ain&#8217;t easy.     </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1hwL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1hwL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png 424w, https://substackcdn.com/image/fetch/$s_!1hwL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png 848w, https://substackcdn.com/image/fetch/$s_!1hwL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png 1272w, https://substackcdn.com/image/fetch/$s_!1hwL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1hwL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png" width="1104" height="597" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:597,&quot;width&quot;:1104,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:285054,&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_!1hwL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png 424w, https://substackcdn.com/image/fetch/$s_!1hwL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png 848w, https://substackcdn.com/image/fetch/$s_!1hwL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.png 1272w, https://substackcdn.com/image/fetch/$s_!1hwL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3a04f3b0-f87f-467c-97e8-35aa4163a349_1104x597.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>Software that comes as a &#8220;single binary&#8221;, is <em><a href="https://redpanda.com/">de rigueur</a> </em>in the event broker world of late. Not without good reason. Single binary software comes bundled with all of its dependencies; you can install Restate and get going. </p><p>Whereas, with Kafka for example, you need to also install the Java Runtime Environment, Kafka Command Line Tools, etc. It just takes more work.</p><p>Regarding the image on the right: <a href="https://grpc.io/">gRPC</a> (Google RPC), HTTP and Kafka are various protocols that we can use to transport messages/invocations to Restate. We have this down. OpenTelemetry I&#8217;ll deal with in a sec. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uGIM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uGIM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 424w, https://substackcdn.com/image/fetch/$s_!uGIM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 848w, https://substackcdn.com/image/fetch/$s_!uGIM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 1272w, https://substackcdn.com/image/fetch/$s_!uGIM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uGIM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png" width="1235" height="682" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:682,&quot;width&quot;:1235,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:243158,&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_!uGIM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 424w, https://substackcdn.com/image/fetch/$s_!uGIM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 848w, https://substackcdn.com/image/fetch/$s_!uGIM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 1272w, https://substackcdn.com/image/fetch/$s_!uGIM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ab1ac8d-cd08-4a95-8cea-4d231e0ed0fe_1235x682.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://opentelemetry.io/">OpenTelemetry</a> (or &#8220;OTel&#8221;) is an absolute game changer, I personally think it still doesn&#8217;t get enough airtime, but anyway. </p><p>OTel is an open source project that provides a set of APIs, libraries and agents to enable the collection of observability data (you guessed it, logs!). In microservices, &#8220;traces&#8221; document the sequence of messages/invocations that span across an application (e.g. each step in our inventory management flow).</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Pub-Sub to my newsletter? (..sorry)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>It&#8217;s not lost on me that this primer on durable execution has been.. durably executing.. for a bit now. You all have Restate down. Sometimes one needs to `exit( )` whilst they&#8217;re ahead (sorry). </p><p>As always, there&#8217;s _so_ much more (<a href="https://kotlinlang.org/docs/coroutines-basics.html">coroutines</a>! <a href="https://www.warpstream.com/">Warpstream</a>! <a href="https://flawless.dev/">Flawless</a>!) that I&#8217;d like to dig into here. However, the good news, readers, is that this primer is itself, a primer for what&#8217;s to come next. </p><p>I&#8217;ve wanted to put digital-pen to digital-paper on a &#8220;Every AWS Service Ever&#8221; post since the beginnings of Why Now. Post-studying the importance of &#8220;product atomicity&#8221;, now seems like no better time to do it. </p><p>10 primers down, and 11 more to come this year. Thank you for reading along, friends.  </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Restate your allegiance to Why Now: </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[Malloy Data]]></title><description><![CDATA["An elephant on clay feet"]]></description><link>https://whynowtech.substack.com/p/malloy-data</link><guid isPermaLink="false">https://whynowtech.substack.com/p/malloy-data</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Thu, 26 Oct 2023 16:03:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!mb_n!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>Welcome to new subs + thanks a million for the <a href="https://whynowtech.substack.com/p/post-transformers-hyena-hierarchy">Hyena</a> love! This thing has grown a whole lot faster than my inner-pessimist could have imagined. So, thank you!</em></p><p><em><strong>If you enjoy these primers, I&#8217;d appreciate it if you favourite this post&#8217;s <a href="https://twitter.com/alex__mackenzie">tweet</a> or <a href="https://www.linkedin.com/in/alex-mackenzie-6aa80ab4/recent-activity/all/">LinkedIn post</a> to help spread the good (?) word of Why Now!</strong></em></p><p><em>I&#8217;m at alex@tapestry.vc should you ever wish to chat, always up for saying hello.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mb_n!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png 424w, https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png 848w, https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png 1272w, https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png" width="1280" height="640" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:640,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Lots going on!! Metrics, Malloy, Sanity Checks, CTEs, and Making Good  Decisions.&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="Lots going on!! Metrics, Malloy, Sanity Checks, CTEs, and Making Good  Decisions." title="Lots going on!! Metrics, Malloy, Sanity Checks, CTEs, and Making Good  Decisions." srcset="https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png 424w, https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png 848w, https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.png 1272w, https://substackcdn.com/image/fetch/$s_!mb_n!,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%2F1f991d84-1b74-401e-8a26-e22f8b15a4c7_1280x640.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>I don&#8217;t mean to alarm you but, &#8220;accidents of history&#8221; are among us. </p><p>Countless decisions make sense when tethered to a particular moment in time. However, if we were to rethink them today from, dare I say it, first principles, we would conclude that we have been subject to one calcified ruse after another. </p><p>Par example, that QWERTY keyboard of yours. It was originally designed to prevent the jamming of mechanical keys in typewriters. I know it&#8217;s fundamentally flawed, but good luck coercing me into switching to DVORAK.</p><p>What else? We created legal tender to facilitate a double coincidence of wants, with internet-scale liquidity, we have this. We&#8217;ve developed modern algorithms to replace <a href="https://abovethecrowd.com/2021/06/03/customers-love-free-stuff-but-thats-not-your-problem/#:~:text=Regardless%20of%20whether,to%20your%20customers.">antiquated IPOs</a>, but all the best convincing your resident Lead Left to change their ways. Don&#8217;t <a href="https://whynowtech.substack.com/p/nix">get me started on</a> Dockerfiles or, better yet, the imperial system. </p><p>Whilst perhaps not quite as existential as <s>Dockerfiles</s> legal tender, I view SQL as comparably archaic. ORMs, SQL supersets, semantic layers and query engines all feel like calcification to me. Band-Aids vs. MMR II. </p><p>Instead of relying on Trino to rewrite our SQL for us, what if we rewrote the language itself? Thankfully, <a href="https://twitter.com/lloydtabb?lang=en">Lloyd Tabb</a> (of Looker fame), <a href="https://www.linkedin.com/in/michael-toy-27b3407/">Michael Toy</a>, <a href="https://carlineng.com/">Carlin Eng</a>, and the team at GCP asked themselves a similar question: </p><p><em>&#8220;If we knew all the things we know about data, and about programming with data, and about programming languages in general, and we were designing a query language today, what would it look like?&#8221;.</em></p><p>More broadly, this line of questioning is one that we as investors should stuff into our back pockets. Lodge it right next to Charlie&#8217;s <a href="https://www.safalniveshak.com/are-you-a-frog-in-boiling-water/#:~:text=In%20this%20speech%2C%20Munger%20cited,given%20way%20back%20in%201995.">boiling frog</a>. In this instance, the result of Lloyd&#8217;s question is <a href="https://www.malloydata.dev/home">Malloy</a> &#8212; a language for describing data relationships &amp; transformations. Sounds.. familiar?</p><p>Sit tight, there&#8217;s more. Malloy:  </p><ul><li><p>Compiles to SQL optimised for your database.</p></li><li><p>Has both a semantic data model and query language.</p></li><li><p>Excels at reading and writing nested data sets.</p></li><li><p>Seamlessly handles what are complex/error-prone queries in SQL.</p></li></ul><p>Interesting. It&#8217;s no secret that the proverbial: &#8220;<a href="https://mozartdata.com/what-is-the-modern-data-platform/">modern data stack</a>&#8221; has been in vogue within venture. Rightly so. However, since stumbling upon Malloy, I&#8217;ve wondered how much of this stack can be obviated by swapping out SQL itself? </p><p>Furthermore, why has SQL endured as the incumbent query language since the 1970s? New programming languages spring up often. What&#8217;s unique here? Let&#8217;s dig in.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">INSERT INTO NewsletterSubscribers (EmailAddress) VALUES ('your@email.com');</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>As mentioned, Malloy is a language for describing <strong>data relationships</strong> and <strong>transformations</strong> within <strong>SQL databases</strong>. It:</p><ul><li><p>Compiles to SQL <strong>optimised for your database</strong>.</p></li><li><p>Has both a <strong>semantic data model</strong> and <strong>query language</strong>.</p></li><li><p>Excels at reading and writing <strong>nested data sets</strong>.</p></li><li><p>Seamlessly handles what are <strong>complex/error-prone</strong> queries in SQL.</p></li></ul><p>As always within Why Now, we&#8217;ll build towards an understanding of the definition above via breaking it into its <strong>components</strong>.</p><div><hr></div><p><strong>Section 1 - History of SQL &amp; RDMS</strong></p><p>As Pablo Picasso (&#8220;founding eng&#8221; at IBM, I think) once opined: &#8220;learn the rules like a pro, so you can break them like an artist&#8221;. Similarly, we must first understand <a href="https://www.red-gate.com/simple-talk/opinion/opinion-pieces/chris-date-and-the-relational-model/">SQL &amp; the &#8220;relational model&#8221;</a> writ large if we are to challenge it.</p><p>Up until 1970, database management systems (DBMSs) such as IBM&#8217;s Information Management System (IMS) organised data using &#8220;hierarchical&#8221; (think tree structures) or &#8220;network&#8221; models:</p><pre><code><code>tree_structure.lua

Organization
|
|-- Department: IT
|   |-- Employee: John Doe
|   |   |-- Task: Develop Software
|   |   |-- Task: Maintain Systems
|   |-- Employee: Jane Smith
|       |-- Task: Network Management
|
|-- Department: HR
    |-- Employee: Mike Johnson
    |   |-- Task: Recruitment
    |-- Employee: Sarah Lee
        |-- Task: Employee Relations </code>   </code></pre><p>With what we know now (recall, &#8220;accidents of history&#8221;), it&#8217;s clear that this is an incredibly rigid, and rather abstruse data model to grok at scale. Imagine attempting to parse <a href="https://blog.zomato.com/building-a-cost-effective-logging-platform-using-clickhouse-for-petabyte-scale#:~:text=At%20Zomato%2C%20our%20internal%20microservices%20and%20monolithic%20applications%20collectively%20produce%20a%20significant%20amount%20of%20logs%20each%20day.%20With%20a%20maximum%20production%20rate%20of%20150%20million%20logs%20per%20minute%2C%20this%20leads%20to%20the%20production%20of%20over%2050%20TB%20of%20uncompressed%20logs%20per%20day.%C2%A0">Zomato&#8217;s 150M logs p/m</a> if represented this way (!).  </p><p>IBs rejoice, Edgar Codd came along in 1970 with the paper: &#8220;<a href="https://www.seas.upenn.edu/~zives/03f/cis550/codd.pdf">A Relational Model of Data for Large Shared Data Banks</a>&#8221;. Edgar proposed that data should be presented to end-users as &#8220;relations&#8221;, which are the database &#8220;tables&#8221; (yes, like Excel) that we&#8217;re all too familiar with today.</p><p>Edgar stated that each row of a table should represent an instance of data (ie a &#8220;record&#8221;) and each column, an attribute (ie a &#8220;property&#8221;). To avoid duplicates, each record should contain a unique identifier, known as a &#8220;primary key&#8221; (e.g., &#8220;student_id&#8221; below).</p><pre><code>relational_structure.lua

| student_id | name | age | major           |
|------------|------|-----|-----------------|
| 1          | John | 21  | Computer Science|
| 2          | Jane | 22  | Mathematics     |
| 3          | Mike | 20  | Physics         |   </code></pre><p>Edgar also equipped us with a set of operations that could be used to manipulate these &#8220;relations&#8221; (remember, tables) in order to retrieve &amp; modify data. Operations such as: selection, projection, union, set difference, Cartesian product, and join. Hmm. Familiar?<br></p><blockquote><p><strong>Technical Detail:</strong> What rhymes here, is that Edgar advocated for the <em>separation</em> of database schema &amp; physical storage. Many years later in 2012, Snowflake would pioneer the <a href="https://www.snowflake.com/product/architecture/#:~:text=It%20features%20storage%2C%20compute%2C%20and%20global%20services%20layers%20that%20are%20physically%20separated%20but%20logically%20integrated">separation of storage and compute</a>, and more recently, Firebolt has <a href="https://docs.firebolt.io/using-indexes/using-indexes.html">separated indices</a> also. </p><p>As Josh Wolfe would instruct, <a href="https://podcasts.apple.com/us/podcast/josh-wolfe-the-tech-imperative/id1154105909?i=1000436137469">pay attention to directions of progress</a>. Accordingly, what are we separating next?</p></blockquote><p><br>Whilst Edgar&#8217;s seminal work precipitated the modern relational database industry, he is in fact, not the creator of SQL himself. This kinda all balances out. As, as already alluded to: &#8220;<a href="https://www.red-gate.com/simple-talk/opinion/opinion-pieces/chris-date-and-the-relational-model/#:~:text=relational%20at%20all-,I%20honestly%20believe%20SQL%20has%20no%20real%20right%20to%20be%20called%20relational%20at%20all,-There%E2%80%99s%20something%20else">SQL has no real right to be called relational at all</a>&#8221;. It&#8217;s implausible that the father of relational algebra would make such a series of blunders.</p><p>Rather, <a href="https://en.wikipedia.org/wiki/Big_Blue_(disambiguation)">Big Blue</a>&#8217;s Chamberlin &amp; Boyce developed what was originally dubbed &#8220;Structured <em>English</em> Query Language&#8221; in 1974. Yes folks, it is <em>See-quill </em>vs. <em>es-que-el</em>. ...Clearly. </p><p>IBM&#8217;s &#8220;System R&#8221; was one of the first RDMSs &amp; implementations of SQL (following the University of Michigan&#8217;s &#8220;Micro DBMS&#8221;). However, by 1979, the fledgling <a href="https://en.wikipedia.org/wiki/Oracle_Corporation">Relational Software Inc</a> released the first commercially available implementation of SQL. Bravo, Larry.</p><p>Ok, so what&#8217;s so wrong with Chamberlin &amp; Boyce&#8217;s <a href="https://en.wikipedia.org/wiki/Frankenstein#:~:text=Frankenstein%3B%20or%2C%20The%20Modern%20Prometheus,by%20English%20author%20Mary%20Shelley.">Modern Prometheus</a>?</p><div><hr></div><p><strong>Section 2 - SQL &amp; Its Issues </strong></p><p>Good news folk. Whilst <a href="https://whynowtech.substack.com/p/nix">Nix expressions</a> or <a href="https://whynowtech.substack.com/p/zig">Zig&#8217;s syntax</a> might&#8217;ve required some labour to wield, SQL is, frankly, tr&#232;s facile. This was very much intended by Chamberlin &amp; Boyce who <a href="https://s3.us.cloud-object-storage.appdomain.cloud/res-files/2705-sequel-1974.pdf">designed the language</a> for &#8220;ad-hoc&#8221; queries, often made by &#8220;non-professional&#8221; users. </p><p>Note the misplaced design decision? Herein lies a derivative of <a href="https://en.wikipedia.org/wiki/Jevons_paradox">Jevon&#8217;s Paradox</a> at play. Lowering the barrier of entry to &#8220;data programming&#8221;, increased the number of sophisticated &#8220;data programmers&#8221; over time. Unsurprisingly, these sophisticated users aren&#8217;t too content with SQL &#8212; it wasn&#8217;t designed for them, after all.  </p><p>Ok, moving swiftly on from economic theory to programming reality. Welcome, class, to SQL 101. </p><p>SQL&#8217;s functionality is essentially <code>GROUP</code>&#8217;<code>d</code> into 3 components: 1) Data Definition (ie describe my data), 2) Data Manipulation (ie change my data) &amp; 3) Data Querying (ie get my data). </p><p>Defining our data could look something like this:</p><pre><code>CREATE TABLE table_name (
    column1 datatype,
    column2 datatype,
    ...
);</code></pre><p>Here, we have created a table called <code>&#8220;table_name&#8221;</code> with two columns: <code>&#8220;column1&#8221;</code> &amp; <code>&#8220;column2&#8221;</code>. We can specify the data types (recall &#8220;types&#8221; from our <a href="https://whynowtech.substack.com/p/deno">Deno primer</a>) that should be inserted into each column (e.g., dates, integers, strings).  </p><p>Next, we manipulate our data like so:</p><pre><code>INSERT INTO table_name (column1, column2,...)
VALUES (value1, value2,...); </code></pre><p>Here, we&#8217;re <em>manipulating</em> the data structure that we originally <em>defined</em> by inserting &#8220;values&#8221; (ie data) that, all going well, conform to the data types we specified above.  </p><p>Great. Now we have data stored in our relational database (think PostgreSQL or BigQuery). In order to actually use this data, be it to power our application or, better yet, <a href="https://stackoverflow.com/questions/68898451/sql-get-number-of-items-with-sales-over-certain-quantity">strike fear into</a> unsuspecting sales reps, we need to <em>query </em>it. A la:</p><pre><code>SELECT column1, column2, ...
FROM table_name
WHERE condition;</code></pre><p>All pretty straightforward, right? Things get a little more.. complicated when you realise that, despite adhering to a <a href="https://blog.ansi.org/sql-standard-iso-iec-9075-2023-ansi-x3-135/">standards body</a>, the SQL you write that works for PostgreSQL, may not work for MySQL.</p><p>For example, if you want to concatenate strings in PostgreSQL you can use the <code>&#8220;concat()&#8221;</code> function or use the following &#8220;pipe&#8221; (ie <code>||)</code> operator:</p><pre><code>postgres_example.sql

SELECT 'Hello' || ' ' || 'World';</code></pre><p>Whereas MySQL doesn&#8217;t use the pipe operator by default (it can be enabled):</p><pre><code>mysql_example.sql

SELECT CONCAT('Hello', ' ', 'World');</code></pre><p><a href="https://news.ycombinator.com/item?id=28058329#:~:text=should%20learn%20SQL-,There's%20a%20lot%20wrong%20with%20SQL.,for%20future%20growth%20and%20development.">Countless examples exist</a> to enumerate my point. Database vendors claim that these differences are due to &#8220;optimisations&#8221; for their DBMS. Sure, but do you think they&#8217;re mad about simultaneously <a href="https://stackoverflow.com/questions/772111/switching-from-mysql-to-postgresql-tips-tricks-and-gotchas#:~:text=It%20is%20going,continue%20regular%20development.">creating switching costs</a>? That sweet, sweet <a href="https://blog.publiccomps.com/snowflake-s1-ipo-teardown/#:~:text=Pretty%20incredible%20Snowflake%20has%20158%25%20net%20dollar%20retention.%20SNOW%20is%20growing%20121%25%20YoY%20so%20half%20of%20revenue%20growth%20is%20from%20getting%20existing%20customers%20to%20expand%20their%20data%20usage.">158% NDR</a>.   </p><p>Fortunately for SQL, its soft-underbelly is often shielded by object-relational mapping (or &#8220;ORMs&#8221;) tools like <a href="https://www.sqlalchemy.org/">SQLAlchemy</a> or <a href="https://www.prisma.io/">Prisma</a>. These tools enable developers to write Python, etc., vs. raw SQL (hence, the &#8220;mapping&#8221;), whilst also acting as database abstraction layers. </p><p>See the &#8220;calcification&#8221; now? Or as Paolo Atzeni puts it: SQL is <a href="https://dl.acm.org/doi/10.1145/2503792.2503808">an elephant on clay feet</a>.</p><blockquote><p><strong>Technical Detail:</strong> See below a SQL &#8220;upsert&#8221; (portmanteau of update &amp; insert) I recently wrote using SQLAlchemy. Note I&#8217;m using the &#8220;Pythonic&#8221; function <code>text()</code> vs. writing raw SQL.<code> </code>  </p></blockquote><pre><code>scraper.py

neon_conn.execute(
                text(
                "INSERT INTO nix_tweets_two (id, tweetid, tweettext, userurl) VALUES (:id, :tweetid, :tweettext, :userurl) ON CONFLICT (tweetid) DO NOTHING"
                ),
                [{"id":nix_tweets_uuid, "tweetid": int(tweet_id), "tweettext": tweet_text, "userurl": user_url}]
                )
        neon_conn.commit()</code></pre><p>Next, we get onto the subject of &#8220;nested queries&#8221; (I&#8217;m a hit at dinner parties). As any of you who&#8217;ve waded through my <a href="https://whynowtech.substack.com/p/zig">Zig primer</a> will know, I&#8217;m a sucker for eloquent programming syntaxes. SQL&#8217;s &#8220;non-<em>pro</em>fessional&#8221; syntax is.. <em>pro</em>ficiently offensive. </p><p>Have a look at how SQL formats nested queries:  </p><pre><code>nested_query_example.sql

SELECT name, salary 
FROM employees 
WHERE salary &gt; (SELECT AVG(salary) FROM employees);</code></pre><p>Perhaps I&#8217;m being a little pedantic, but parsing this query certainly isn&#8217;t intuitive. For a start, what should I (or the &#8220;parser&#8221; itself) compute first? Also, whilst I&#8217;m on this brazen crusade, shouldn&#8217;t we start the query with the <code>FROM</code> clause?<code> </code> </p><p>However, things can get much more convoluted: </p><pre><code>compex_nested_query_example.sql

SELECT customer_name, total_order_value
FROM (
    SELECT o.customer_name, 
           SUM(oi.price * oi.quantity) AS total_order_value
    FROM orders o
    JOIN order_items oi ON o.order_id = oi.order_id
    GROUP BY o.customer_name
) AS customer_orders
WHERE total_order_value &gt; (
    SELECT AVG(total_order_value) 
    FROM (
        SELECT o.order_id, 
               SUM(oi.price * oi.quantity) AS total_order_value
        FROM orders o
        JOIN order_items oi ON o.order_id = oi.order_id
        GROUP BY o.order_id
    ) AS order_values
);</code></pre><p>Anyone else feel a sense of malaise? Don&#8217;t worry, my head is pounding too. On a positive note, even dedicated SQL parsing algorithms struggle to comprehend walls of SQL like this. </p><p>Perhaps it&#8217;s increasingly clear why we should <code>DROP</code> this language? (sorry, couldn&#8217;t resist)</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><code>'Hello please' || ' ' || 'subscribe'</code></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Let&#8217;s scratch off some of our newfound understanding from our original definition: </p><p>As mentioned, Malloy is a language for describing <strong><s>data relationships</s></strong> and <strong><s>transformations</s></strong> within <strong><s>SQL databases</s></strong>. It:</p><ul><li><p>Compiles to SQL <strong><s>optimised for your database</s></strong>.</p></li><li><p>Has both a <strong>semantic data model</strong> and <strong><s>query language</s></strong>.</p></li><li><p>Excels at reading and writing <strong><s>nested data sets</s></strong>.</p></li><li><p>Seamlessly handles what are <strong><s>complex/error-prone</s></strong> queries in SQL.</p><p></p></li></ul><div><hr></div><p><strong>Section 3 - Introducing the Semantic Layer</strong></p><p>Let&#8217;s begin by unpacking the &#8220;semantic data model&#8221;. </p><p>We&#8217;ll get into the nitty-gritty, but &#8220;semantic&#8221; is the key word here. Ever squinted at thousands of table rows &amp; struggled to understand the &#8220;meaning&#8221; of the data? Don&#8217;t fret, this is a safe space, I have too.  </p><p>Let&#8217;s continue our therapy session. Perhaps you&#8217;ve also felt the anxiety of wondering if the SQL you&#8217;ve written is calculating subjective metrics like: &#8220;<a href="https://review.firstround.com/From-0-to-1B-Slacks-Founder-Shares-Their-Epic-Launch-Strategy#:~:text=For%20Slack%2C%20the%20number%20is,tried%20it%2C%E2%80%9D%20Butterfield%20says.">a magic number</a>&#8221; or &#8220;MAUs&#8221;, correctly? Rather stressful. </p><p>Ideally, we&#8217;d make our data easy to grok. We can do this by translating abstruse data schemas and walls of SQL into intuitive natural language concepts and instructions. Hence, &#8220;semantic model&#8221; (or <a href="https://www.getdbt.com/product/semantic-layer">&#8220;semantic layer&#8221;</a>). Ok, nice, but how does this all work?</p><p>Brace yourselves for another layer of &#8220;calcification&#8221;.   </p><p>Many credit BusinessObjects (<a href="https://www.computerworld.com/article/2539248/update--sap-to-buy-business-objects-in--6-8b-deal.html">acquired for ~$6B by SAP in 2007</a>) for creating the original semantic layer, called &#8220;Universe&#8221;. However, I think Looker&#8217;s &#8220;LookML&#8221; (created in 2012) demonstrates its ideals best. </p><p>LookML is essentially a SQL abstraction. Folk using Looker for BI purposes can write the language vs. writing <a href="https://www.kobejones.com.au/how-to-choose-sushi-grade-seafood/#:~:text='Sushi%2Dgrade'%20fish%20is,%C2%B0F%20for%2015%20hours.">sushi-grade SQL</a>. Nice lock-in by Looker, huh? As discussed, this is common in database land: <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html">Elastic&#8217;s Query DSL</a>, <a href="https://neo4j.com/developer/cypher/">Neo4j&#8217;s Cypher</a>, <a href="https://cassandra.apache.org/doc/latest/cassandra/cql/">CQL</a>, et cetera. </p><p>Anyway, LookML exposes many core concepts that bestow semantic meaning upon raw SQL. We&#8217;ll focus on LookML&#8217;s &#8220;measures&#8221; (ie data calculations) as but one example. Let&#8217;s begin: </p><pre><code>sales.view.lkml

view: sales {
  measure: total_sales {
    type: sum
    sql: ${TABLE}.sale_price ;;
  }
</code></pre><p>Here we have a LookML file (hence &#8220;.lkml&#8221;) that stores a &#8220;view&#8221; (ie a table) called <code>sales</code> that&#8217;s derived from another table&#8217;s <code>sales_price</code> column.</p><p>Within this view, we have a &#8220;measure&#8221; called <code>total_sales</code>. Note the metadata within the &#8220;measure&#8221; that makes it quite intuitive to understand what&#8217;s happening here (e.g., <code>type:</code> <code>sum</code>).  </p><p>This metadata also reduces the length &amp; complexity of the raw SQL that would be written otherwise: </p><pre><code>sales_alternative.sql

SELECT SUM(sale_price) AS total_sales
FROM sales;</code></pre><p>Hmm. Nice&#8230; maybe? To close the loop, more recently, dbt <a href="https://www.getdbt.com/product/semantic-layer">inherited semantic layer capabilities</a> via its <a href="https://www.getdbt.com/blog/dbt-acquisition-transform">acquisition of Transform</a>. Much like Looker, dbt also encourages the extension of SQL via the Python-based templating engine, <a href="https://jinja.palletsprojects.com/">Jinja</a>. </p><p>Super. With LookML it.. looks-ml.. like we have solved many of SQL&#8217;s shortcomings, right? Well, no. Firstly, as belaboured at this point, we&#8217;re not fixing the root cause of our woes: SQL itself.  </p><p>Secondly, the issue with many of these SQL extensions &amp; abstractions is that they&#8217;re tethered to specific vendors. If I&#8217;m the de novo database on the block, do I really want to create dependency on a future competitor? Nope. As a result, our efforts don&#8217;t yield standardisation around a better way of doing things.   </p><p>It&#8217;s clear that we need a new, open, standard.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">ask: subscribe {plea_type: tragic}</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Ok, one final scratching-off exercise below. Seems like we&#8217;re now ready to tackle Malloy? </p><p>As mentioned, Malloy is a language for describing <strong><s>data relationships</s></strong> and <strong><s>transformations</s></strong> within <strong><s>SQL databases</s></strong>. It:</p><ul><li><p>Compiles to SQL <strong><s>optimised for your database</s></strong>.</p></li><li><p>Has both a <strong><s>semantic data model</s></strong> and <strong><s>query language</s></strong>.</p></li><li><p>Excels at reading and writing <strong><s>nested data sets</s></strong>.</p></li><li><p>Seamlessly handles what are <strong><s>complex/error-prone</s></strong> queries in SQL.</p></li></ul><div><hr></div><p><strong>Section 4 - Malloy</strong></p><p>I&#8217;ll be honest, I didn&#8217;t think I&#8217;d get this excited about a query language. That said, I should know better at this point: <a href="https://whynowtech.substack.com/p/zig">Zig</a>, Godot&#8217;s <a href="https://whynowtech.substack.com/p/bonus-remaking-pokemon-yellow-in">GDScript</a>, &amp; <a href="https://whynowtech.substack.com/p/deno">Deno</a> (well, <a href="https://fresh.deno.dev/">Fresh</a>) have all played lead roles in Why Now. </p><p>The world runs on software, but software runs in the direction that it&#8217;s guided towards. Minimise bugs and you&#8217;ll create <a href="https://youtu.be/YXrb-DqsBNU">mission critical applications</a>, <a href="https://medium.com/@ohermans1/the-importance-of-typescript-a-closer-look-at-type-safety-and-error-handling-85a3e4b4280b">enforce type safety</a> and you&#8217;ll build a whole lotta enterprise SaaS. </p><p>Languages shape software, making them rather fascinating. This impact, served with <a href="https://sites.google.com/view/malloydata/home?authuser=0&amp;pli=1">comparisons of magic</a>, made Malloy rather difficult to resist. To be fair, I think Lloyd may be onto something. Let&#8217;s delve a little deeper.   </p><p>Ok, so, firstly.. Malloy starts with a <code>run</code> clause, which essentially serves the same purpose as (although is more &#8220;powerful&#8221; than) SQL&#8217;s <code>FROM</code> clause. As mentioned already, this just makes logical sense: </p><pre><code>run: duckdb.table('../data/airports.parquet') -&gt; {
  select:
    id
    code
    city
  limit: 10
}</code></pre><blockquote><p><strong>Technical Detail:</strong> Don&#8217;t worry about the &#8220;duckdb&#8221; reference (<a href="https://hannes.muehleisen.org/">thanks Hannes</a>), this is &#8220;just&#8221; a database that&#8217;s embedded locally on your device (laptop, phone, etc). <br><br>So, all we&#8217;re doing here is accessing an <code>airports</code> table that&#8217;s stored as a Parquet file. Parquet files are columnar file formats which we won&#8217;t get into now, but you really should <a href="https://www.databricks.com/glossary/what-is-parquet">read up on them</a> if unfamiliar.   </p></blockquote><p>Let&#8217;s continue examining the &#8220;scaffolding&#8221; of Malloy for a tad longer before we delve into the meatier stuff. </p><p>As I&#8217;ve <a href="https://whynowtech.substack.com/p/zig">alluded to previously</a>, language ambiguity creates bugs and hinders readability. How so? Well, if multiple ways of achieving the same outcome exist, the &#8220;reader&#8221; of a particular piece of code has to do a little more grease-work to understand it.</p><p>For example, in SQL, the <code>SELECT</code> clause can be used for two distinct use cases. When married with the <code>GROUP</code> <code>BY</code> clause, <code>SELECT</code> is used for aggregation purposes (note the &#8220;<code>SUM(sales) as total_sales</code>&#8221; below). If the <code>GROUP</code> <code>BY</code> clause isn&#8217;t present, then <code>SELECT</code> is used for plain ole data retrieval.</p><p>Par example, imagine we have a table like so:</p><pre><code><code>+---------+-------+
| country | sales |
+---------+-------+
| USA     | 100   |
| USA     | 50    |
| Canada  | 70    |
| UK      | 30    |
+---------+-------+</code></code></pre><p>If we query this table with the following SQL (note the <code>SELECT</code> <em>&amp;</em> <code>GROUP</code> <code>BY</code>) like so: </p><pre><code><code>example.sql

SELECT country, SUM(sales) as total_sales
FROM data_table
GROUP BY country;</code></code></pre><p>We end up aggregating (in this case, <code>SUM-</code>ming) the USA rows. Why? Because they&#8217;re present more than once (hence the 150 total sales):</p><pre><code><code>+---------+-------------+
| country | total_sales |
+---------+-------------+
| USA     | 150         |
| Canada  | 70          |
| UK      | 30          |
+---------+-------------+</code></code></pre><p>Accordingly, notice that the <code>SELECT</code> statement has a lack of &#8220;identity&#8221; to some degree here? It serves a couple of purposes. This tends to occur when a programming language is essentially developed in tandem with its own use case. </p><p>My-guy-Malloy, on the other hand, has the benefit of hindsight. Thus, Malloy is a little more.. explicit with aggregates:</p><pre><code><code>run: duckdb.table('../data/airports.parquet') -&gt; {
  group_by:
    state
    county
  aggregate:
    airport_count is count()
    average_elevation is avg(elevation)
}</code></code></pre><p>Comparatively, this statement is easier to build an intuition for, despite many of you likely dabbling with a <code>SELECT</code> clause or two in your time? Kinda cool.</p><div><hr></div><p>No doubt some of you think I&#8217;m being pedantic thus far, perhaps that&#8217;s fair. We&#8217;ll inch towards Malloy&#8217;s more poignant features. </p><p>Recall from my opening preamble this sub-point: &#8220;<em>about programming languages in general</em>&#8221;? </p><p>There&#8217;s a lot we do syntactically in general-purpose programming languages that, for whatever reason, haven&#8217;t found their way into SQL. Par example, in Python, Go, JavaScript, Rust, Kotlin, etc., we define variables like so: <strong>variable name = value.</strong> </p><p>In SQL, unfortunately, we invert this when creating column aliases (ie &#8220;max elevation&#8221; below):</p><pre><code>waitbutwhy.sql

SELECT 
   max(base."elevation") as "max_elevation"
FROM '../data/airports.parquet' as base
ORDER BY 1 desc NULLS LAST</code></pre><p>Why create this overhead? Again, think about it. If a software engineer was creating SQL from scratch today, this naming pattern wouldn&#8217;t fly. In Malloy, aliases are defined like variables are in programming languages:</p><pre><code>run: duckdb.table('../data/airports.parquet') -&gt; {
  aggregate: <strong>max_elevation is max(elevation)</strong>
}       <em> </em></code></pre><p>Nice, progress. What else can we glean from programming languages? </p><p>Well, recall that &#8220;nested datasets&#8221; (ie datasets derived from other datasets) in SQL can become a bit of a mess:</p><pre><code>example.sql

SELECT customer_name, total_order_value
FROM (
    SELECT o.customer_name, 
           SUM(oi.price * oi.quantity) AS total_order_value
    FROM orders o
    JOIN order_items oi ON o.order_id = oi.order_id
    GROUP BY o.customer_name
) AS customer_orders</code></pre><p>But why are they particularly unwieldy in SQL? Nested calculations aren&#8217;t unique to data queries. In programming languages, like Python for example, you&#8217;ll often &#8220;nest&#8221; a function within another function (often called a &#8220;callback function&#8221;).   </p><p>To make these nested functions more legible, it&#8217;s very much common practice to assign a variable name to the &#8220;callback&#8221; like so:</p><pre><code>example.py

def callback_function():
    print("Callback executed!")

def main_function(callback):
    # Do something...
    callback()  # Execute the callback function

main_function(callback_function)  # Outputs: "Callback executed!"</code></pre><p>Notice how using named expressions makes the &#8220;nested function&#8221; (ie <code>main_function()</code>), easier to wade through? The same is true for SQL.</p><p>Whilst you certainly <em>can</em> <a href="https://stackoverflow.com/questions/32522742/how-to-use-an-alias-name-for-a-calculated-expression-in-sql#:~:text=You%20can%20give%20an%20alias%20for%20the%20calculated%20field%20and%20use%20that%20alias%20in%20your%20outer%20query.%20For%20example%3B">assign names to expressions</a> in SQL, they&#8217;re not required. People are some confluence of busy &amp; lazy; if you don&#8217;t encourage a desired action, you may not see it. Malloy, on the other hand, mandates named expressions. </p><p>The below code literally won&#8217;t run if the output of its &#8220;aggregate&#8221; calculation isn&#8217;t named (ie &#8220;<code>max_elevation</code>&#8221;):   </p><pre><code><code># This code works:

run: duckdb.table('../data/airports.parquet') -&gt; {
  aggregate: max_elevation is max(elevation)
}

# This code doesn't work:

run: duckdb.table('../data/airports.parquet') -&gt; {
  aggregate: max(elevation)
}
       </code></code></pre><p>Perhaps these examples still seem like small wins, but they embody how historical decisions benefit from present context. In tandem, these wins inculcate a broader point: Malloy has rethought SQL to the nth degree. No suboptimal clause or pattern is safe.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><code>def subscribe(please):</code></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Whilst I tend to feel the magnetic pull of micro-optimisations (the trade-offs are fascinating); Malloy also introduces new functionality that we should make time to appreciate. Namely, a semantic layer. </p><p>Recall, SQL doesn&#8217;t have a semantic layer itself. It outsources this work to companies that build (<a href="https://www.getdbt.com/pricing#:~:text=All%20features%20in%20Developer,Layer%2C%20powered%20by%20MetricFlow">&amp; often monetise</a>) semantic layers. Nothing wrong with this per se, but it can precipitate the dreaded &#8220;vendor lock-in&#8221;.    </p><p>Unsurprisingly, Malloy&#8217;s semantic layer rhymes with Looker&#8217;s. When you want to save common calculations (remember &#8220;measures&#8221; in LookML), you can do so, along with &#8220;dimensions&#8221;,  &#8220;joins&#8221;, etc.</p><p>Let&#8217;s &#8216;av a look:</p><pre><code>source: airports is duckdb.table('../data/airports.parquet') extend {
  dimension: county_and_state is concat(county, ', ', state)
  measure: airport_count is count()
  measure: average_elevation is avg(elevation)
}</code></pre><p>We initialise semantic layers in Malloy with the <code>source</code> keyword. No ambiguity here, if you spot <code>source</code>, you know some sweet, sweet, semantic meaning is going down.</p><p>Note that, again, much like in LookML, our semantic layer is derived from some original table (ie <code>duckdb.table('../data/airports.parquet')</code>). </p><p>We then &#8220;extend&#8221; this table with one &#8220;dimension&#8221; (<code>county_and_state</code>), and two &#8220;measures&#8221; (<code>airport_count</code>, <code>average_elevation</code>). </p><p>Good news is, we&#8217;ve already done the work to know what measures are. They are simply instructions for how to calculate subjective metrics (remember, &#8220;MAUs&#8221; for example).</p><p>We can then use these saved &#8220;measures&#8221; in future Malloy queries like so:</p><pre><code>run: airports -&gt; { 
  group_by: county_and_state
  aggregate: airport_count
}</code></pre><p>Dimensions are new to this primer, but common in semantic layers more generally. They&#8217;re used to further describe and transform your data. More good news. They&#8217;re quite simple to grok once placed under the lens of our example code:</p><pre><code><code>source: airports is duckdb.table('../data/airports.parquet') extend {
  dimension: county_and_state is concat(county, ', ', state)
  measure: airport_count is count()
  measure: average_elevation is avg(elevation)
}</code></code></pre><p>Here, the &#8220;dimension&#8221; (think new column) <code>country_and_state</code>, is the concatenation of two separate columns in our <code>airports</code> table (<code>country</code> and <code>state</code>). The resulting column, or &#8220;dimension&#8221;, of this column will look like so: </p><pre><code>+---------------------+
|  county_and_state   |
+---------------------+
|  Santa A, CA        |
|  Santa B, CA        |
|  York, NY           |
+---------------------+</code></pre><p>All quite simple, but some powerful &amp; convenient functionality to have embedded in a query language directly. Nice work, Malloy. </p><div><hr></div><p>No doubt some of you have picked up on the, <em>? subtle ?,</em> irony present within this primer. A primer lambasting an unwieldy query language has become.. unwieldy. </p><p>There is, _so_ much more for us to dig into re. Malloy. The language&#8217;s approach towards query pipelines is particularly cool; the fact that you can structure your queries with freedom is too; and you&#8217;re all lucky I omitted several other micro-optimisations.   </p><p>I&#8217;d encourage you to <a href="https://malloydata.github.io/documentation/user_guides/basic.html">walkthrough Malloy&#8217;s quickstart</a> at your leisure. </p><p>Lloyd, Michael, Carlin &amp; the team are breaking rules in a way that would make Pablo himself proud. Art has a plethora of forms.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Next primer will likely be on a new ~database. Subscribe, tell your friends, etc. </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><p></p>]]></content:encoded></item><item><title><![CDATA[Post-Transformers - Hyena Hierarchy]]></title><description><![CDATA[Breaking the Quadratic Barrier]]></description><link>https://whynowtech.substack.com/p/post-transformers-hyena-hierarchy</link><guid isPermaLink="false">https://whynowtech.substack.com/p/post-transformers-hyena-hierarchy</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Mon, 04 Sep 2023 15:13:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!APjE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>Welcome to new subs + thanks a million for the <a href="https://whynowtech.substack.com/p/zig">Zig</a> love! This thing has grown a whole lot faster than my inner-pessimist could have imagined. So, grazie!</em></p><p><em><strong>If you enjoy these primers, I&#8217;d appreciate it if you favourite this post&#8217;s <a href="https://twitter.com/alex__mackenzie">tweet</a> or <a href="https://www.linkedin.com/in/alex-mackenzie-6aa80ab4/recent-activity/all/">LinkedIn post</a> to help spread the good (?) word of Why Now!</strong></em></p><p><em>As always, I&#8217;m at alex@tapestry.vc should you ever wish to chat. In particular, I&#8217;ve spent a lot of time <strong><a href="https://whynowtech.substack.com/p/a-frontend-ide/comments">thinking/writing</a></strong> about what <strong>new</strong> applications could exist thanks to LLMs &#8212; if you have too, I&#8217;d love to say hello.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!APjE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!APjE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png 424w, https://substackcdn.com/image/fetch/$s_!APjE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png 848w, https://substackcdn.com/image/fetch/$s_!APjE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png 1272w, https://substackcdn.com/image/fetch/$s_!APjE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!APjE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png" width="1456" height="701" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:701,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1894096,&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_!APjE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png 424w, https://substackcdn.com/image/fetch/$s_!APjE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png 848w, https://substackcdn.com/image/fetch/$s_!APjE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.png 1272w, https://substackcdn.com/image/fetch/$s_!APjE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F90867d7a-d9be-4c96-b4df-f7cade34aea6_2183x1051.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>Hyena clans are arranged in what&#8217;s known as a &#8220;linear dominance hierarchy&#8221;. This means that there&#8217;s a one-to-one chain of command: Hyena 3 reports to Hyena 2, and Hyena 2 reports to, you guessed it, Hyena 1. </p><p>This structure is also present in baboons, wolves, and perhaps most notably, chickens.. ever wondered where the phrase &#8220;pecking order&#8221; came from? (That one&#8217;s for free).</p><p>Don&#8217;t worry, Why Now isn&#8217;t expanding it&#8217;s purview into primers on the animal kingdom. Although, do expect a foray into some biotech topics soon! </p><p>Instead, I&#8217;ve been ruminating of late on the logical end state (or as Palmer Luckey <a href="https://www.youtube.com/watch?v=dMhVrYhQUsk">puts it</a> &#8212; the &#8220;final platform&#8221;) of LLMs. What will this technology look and feel like when it reaches maturity? What does the &#8220;iPhone&#8221; of Generative AI look like? </p><p>Well, for a start, LLM context-limits don&#8217;t feel particularly mature to me. Rather, they&#8217;re akin to the bandwidth limits that were present in early mobile network generations. Good luck using TikTok, Spotify, Discord, etc., with 2G&#8217;s 50 kbps!    </p><p>So, what&#8217;s being done today to loosen this constraint? </p><p>Well, it&#8217;s fair to say that one solution &#8212; vector databases &#8212; received its fair share of.. <em>attention</em> (sorry). Given how models du jour <a href="https://openai.com/pricing#:~:text=Model,0.12%C2%A0/%201K%20tokens">price</a> (ie per [X]K tokens), perhaps vector dbs will remain the most economically viable solution. However, another approach has recently come into play: <a href="https://arxiv.org/abs/2302.10866">Hyena Hierarchy</a>.   </p><p>Hyena is proposed to be a drop-in replacement (much <a href="https://whynowtech.substack.com/p/zig">like Zig is</a> for C!) for the Transformer&#8217;s key mechanism &#8212; the attention operator &#8212; which, whilst a seminal innovation, is the source of LLMs&#8217; scaling challenges to date.</p><p>Throughout this primer I&#8217;ll walk you through:</p><ul><li><p>How and why we arrived at the attention mechanism (RNNs, LSTMs, GRUs, etc) </p></li><li><p>How the attention mechanism actually works - step by step </p></li><li><p>Why we need an alternative to attention</p></li><li><p>Said alternative to attention - &#8220;Hyena&#8221;</p></li></ul><p>If the fastest growing <a href="https://chat.openai.com/">application</a> of all time was unlocked via &#8220;attention&#8221;, then it&#8217;s incumbent on us (as investors at least) to study where the puck is heading next. </p><p>Let&#8217;s see if attention, in fact, <em>isn&#8217;t</em> all you need?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Hyena 1 says that you should subscribe. Sincerely, Hyena 2.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Hyena is defined as: a <strong>sub-quadratic </strong>drop-in replacement for <strong>attention</strong> constructed by interleaving <strong>implicitly parametrised</strong> <strong>long-convolutions </strong>and <strong>data-controlled gating</strong>. </p><p>Oh boy&#8230;</p><p>Don&#8217;t worry, as always in Why Now, we&#8217;ll build towards an understanding of the (rather abstruse) definition above via breaking it into its components. </p><div><hr></div><p>Before we dig in here, it&#8217;s worth remembering that machine learning may be full of complex math, but all of this math is ultimately <em>attempting </em>to recreate how we as humans, rather effortlessly, make predictions:<br></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BYS2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BYS2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 424w, https://substackcdn.com/image/fetch/$s_!BYS2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 848w, https://substackcdn.com/image/fetch/$s_!BYS2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 1272w, https://substackcdn.com/image/fetch/$s_!BYS2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BYS2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png" width="1456" height="339" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:339,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:153220,&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_!BYS2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 424w, https://substackcdn.com/image/fetch/$s_!BYS2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 848w, https://substackcdn.com/image/fetch/$s_!BYS2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 1272w, https://substackcdn.com/image/fetch/$s_!BYS2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef95575a-7d03-41ce-a3c4-54da438de3ff_2852x664.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">In mathematical notation the above could be: <em>&#963;(w1*a1 + w2*a2 + w3*a3,&#8230; + bias)</em>  </figcaption></figure></div><p></p><p>So, throughout this primer, I&#8217;ll push you to think about how you yourself, very naturally, make specific predictions, before I reveal how a given model does so. If you listen to Deepmind&#8217;s <a href="https://www.deepmind.com/the-podcast">podcast</a>, you&#8217;ll notice that much of the team&#8217;s time is spent ultimately running the same exercise.</p><div><hr></div><p>Conveniently, the &#8220;attention mechanism&#8221; present in Transformers is a good opportunity to begin this exercise. For example, in the sentence: <em>&#8220;hello, please subscribe to my&#8230;&#8221;</em>, if you were to predict the next word in this sentence, I suspect (or hope!) some of you may predict <em>&#8220;newsletter&#8221;</em>.</p><p></p><div class="preformatted-block" data-component-name="PreformattedTextBlockToDOM"><label class="hide-text" contenteditable="false">Text within this block will maintain its original spacing when published</label><pre class="text"><em>                                        [ hello, &#8212; please &#8212; subscribe &#8212; to &#8212; my &#8212; ]                                          </em> </pre></div><p></p><p>Analyse this sentence, what about it would increase your likelihood of making this prediction? Do genuinely give this a go. </p><p>Well, you may pay heed (or, <em>attention</em>) to the word &#8220;subscribe&#8221;, and if you do, you would likely ask yourself&#8230; what&#8217;s possible to subscribe to? [SaaS products, Dollar Shave Club, &#8230;newsletters]. </p><p>In tandem, you might pay attention to the word &#8220;my&#8221; given its relation to, or influence on, the word &#8220;subscribe&#8221;. If you have context (ie you&#8217;ve been &#8220;trained&#8221;) on who I am, you may pick the word &#8220;newsletter&#8221; from your word list. Why? Because you know that I&#8217;m the author of Why Now, not the founder of DSC.</p><p>Similarly, words like &#8220;please&#8221;, &#8220;hello&#8221; or &#8220;to&#8221; should have less attention placed on them. They don&#8217;t exactly contribute here.</p><p>I suspect that for most of you this invention doesn&#8217;t exactly feel, groundbreaking? Good, in many ways the idea itself isn&#8217;t. However, it&#8217;s important to understand on a technical level how we got here, so that we can then better predict what comes after Transformers. </p><p>We&#8217;ll do this first by studying Recurrent Neural Networks (RNNs), and then by delving into the actual architecture of a Transformer.  </p><p>RNNs are often the architecture of choice for making predictions based on sequential data (e.g., sentences, audio, time-series, etc), because, unlike traditional &#8220;feed forward neural networks&#8221; (your run-of-the-mill neural net), they&#8217;re ~capable of preserving an intermediary state (known as a &#8220;hidden state&#8221;):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CZqz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CZqz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png 424w, https://substackcdn.com/image/fetch/$s_!CZqz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png 848w, https://substackcdn.com/image/fetch/$s_!CZqz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png 1272w, https://substackcdn.com/image/fetch/$s_!CZqz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CZqz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png" width="554" height="330.64972527472526" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:869,&quot;width&quot;:1456,&quot;resizeWidth&quot;:554,&quot;bytes&quot;:87684,&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_!CZqz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png 424w, https://substackcdn.com/image/fetch/$s_!CZqz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png 848w, https://substackcdn.com/image/fetch/$s_!CZqz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.png 1272w, https://substackcdn.com/image/fetch/$s_!CZqz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0c24849-ca28-4526-8671-21e13fddfffe_1599x954.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">An RNN. Note that the words above would actually be represented as vectors, so &#8220;hello&#8221; could be: [0.1, 0.7, 1]</figcaption></figure></div><p></p><p>Let&#8217;s go back to our <em>&#8220;hello, please subscribe to my..&#8221; </em>example, to demonstrate (on an admittedly theoretically level), why this state maintenance matters.</p><p>If our RNN &#8220;remembers&#8221; that it&#8217;s already processed the word &#8220;subscribe&#8221;, then when it later processes the word &#8220;my&#8221;, this new word has a little more context. Ie, the model may (theoretically) ask itself: <em>what does Alex own that people could subscribe to?</em></p><p>Without this context (or memory), our model would more generally just try to predict the most likely word to follow &#8220;my&#8221;; errors can occur here as there may be words closer to &#8220;my&#8221; in vector space than &#8220;newsletter&#8221;.</p><div><hr></div><p>Cool, it sounds like due to RNNs&#8217; &#8220;memory&#8221; we can make accurate predictions. Why do we need Transformers at all then? Well, it turns out that RNNs are a tad forgetful &#8212; they suffer from &#8220;memory loss&#8221;. </p><p></p><p></p><blockquote><p><strong>Key Point:</strong> &#8220;Memory loss&#8221; is what it says on the tin. An input (think a given word in a sentence) your neural network has received, is forgotten over time. This is as a result of both the &#8220;vanishing gradient&#8221; and &#8220;exploding gradient&#8221; problems (we&#8217;ll spend time on the vanishing gradient). </p></blockquote><p></p><p></p><p>If you&#8217;re familiar with how neural networks learn (or Vercel&#8217;s <a href="https://vercel.com/design">style guide</a>..), then the word &#8220;gradient&#8221; likely isn&#8217;t new to you. </p><p>A loss function, gradient descent, and backpropagation underpin how model parameters (weights and biases) are updated:</p><p>  </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OISt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OISt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 424w, https://substackcdn.com/image/fetch/$s_!OISt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 848w, https://substackcdn.com/image/fetch/$s_!OISt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 1272w, https://substackcdn.com/image/fetch/$s_!OISt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OISt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png" width="456" height="184.18241042345278" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:248,&quot;width&quot;:614,&quot;resizeWidth&quot;:456,&quot;bytes&quot;:26331,&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_!OISt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 424w, https://substackcdn.com/image/fetch/$s_!OISt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 848w, https://substackcdn.com/image/fetch/$s_!OISt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 1272w, https://substackcdn.com/image/fetch/$s_!OISt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2eb5a26c-31f7-43b9-9aeb-b54edb13c977_614x248.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">I typically remove math in these primers, but I actually think it&#8217;s the best way to convey the relationship between backpropagation &amp; gradient descent!</figcaption></figure></div><p></p><p>Quick level-setter: </p><ol><li><p>Our loss function determines how (in)accurate our model is &#8212; the model&#8217;s &#8220;loss&#8221;. </p></li><li><p>Backpropagation determines the gradient of the loss function with respect to a given weight/bias (ie how &#8220;responsible&#8221; each weight/bias is for the overall loss).</p></li><li><p>Gradient descent is the formula above, it calculates the weights/biases to minimise this loss based on a configured leaning rate. Et voil&#224;! We have learning.  </p></li></ol><p></p><p></p><blockquote><p><strong>Technical Detail:</strong> As some of you may recall from differential calculus, if we want to solve the following equation: <em>y = f(u) and u = f(x), </em>which can also be rewritten as <em>y = f(u(x)), </em>we can leverage the &#8220;chain rule&#8221;. It&#8217;s this very rule that backpropagation is built upon. </p><p>In neural networks, backpropagation calculates the gradients (remember, &#8220;loss responsibility&#8221;), for the outermost layer&#8217;s weights/biases, and then, we use these gradients to help determine the gradients of previous layers, and so on so forth. <br><br>Remember, in neural networks, each neuron is actually function: &#963;(w1*a1 + w2*a2, w3*a2&#8230;.+ bias), whose inputs (specifically the &#8220;a&#8221; which = &#8220;activation&#8221;) is derived from another function. Sounds kind of similar to <em>y = f(u(x))</em>, right? </p></blockquote><p><br>Alas, whilst backpropagation (thanks <a href="https://www.dataversity.net/brief-history-deep-learning/#:~:text=The%201980s%20and,of%20handwritten%20checks.">Yann</a>), was a key innovation for making training scale, it&#8217;s not perfect. Enter vanishing gradients!</p><p>Remember, neural networks consist of many &#8220;hidden layers&#8221; (ie the layers between the input &amp; output layers). So, when applying the chain rule to neural networks our equation may essentially look like, brace yourselves&#8230;</p><p><em>y = f(a(b(c(d(e(f(g(h(i))))))))).. </em>you get me?<em> (this isn&#8217;t the actual formula, but gets the point across)</em></p><p>What essentially happens here is that we use the gradients of the previous neuron (the gradient of the weight and gradient of the bias), to help calculate the gradients of the current neuron. We do so <em>aaaaall</em> the way to the very first hidden layer.</p><p>The &#8220;vanishing&#8221; happens if the gradients across layers are consistently small, as if you multiply say, 0.05 x 0.02, you get 0.001, now imagine taking this 0.001 gradient, and doing the same again &amp; again. Eventually the gradient values get infinitesimally small. Some might even say that they &#8220;vanish&#8221;! </p><p>Why is this an issue? Well, per the gradient descent formula, if we calculate our weights/biases via the gradient value, if the gradient value itself is minuscule, the resulting change in the weight/bias will be too. Hence, our network&#8217;s learning adopts the pace of a <a href="https://en.wikipedia.org/wiki/Gastropoda#:~:text=The%20gastropods%20(%2F%CB%88%C9%A1%C3%A6,p%C9%99d%C9%99%2F).">Gastropoda</a> (keeping the animal kingdom theme alive here). <br></p><blockquote><p><strong>Key Point:</strong> To make matters worse, this problem is exacerbated in RNNs by what&#8217;s known as backpropagation through time (or &#8220;BPTT&#8221;). We don&#8217;t have to get into the weeds on this. Instead, I&#8217;d rather you have a think about why this may be the case? (psst, focus on <em>time</em>). <a href="https://youtu.be/nFTQ7kHQWtc?t=2324">Here&#8217;s</a> the answer courtesy of Lex. Thanks Lex. </p></blockquote><p><em><br>** <s>RNNs</s>, <s>Backpropagation</s>, <s>Vanishing Gradients</s> - nice work! **</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Increase your <em>&#8220;&#945;&#8221; </em>by subscribing? </p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Hyena is defined as: a <strong>sub-quadratic </strong>drop-in replacement for <strong><s>attention</s></strong> constructed by interleaving <strong>implicitly parametrised</strong> <strong>long-convolutions </strong>and <strong>data-controlled gating</strong>. </p><p>Ok, so we&#8217;ve learned that traditional RNNs, whilst directionally correct, suffer from memory loss, due to the vanishing (or exploding) gradient problem. If these models can&#8217;t recall &#8220;long-term dependencies&#8221; (e.g., early words in a paragraph)<em>, </em>then they can&#8217;t really be used for making predictions based on sequential data. A shame.</p><p>Enter &#8220;gating&#8221; &#8212; spot it above? At a high-level, &#8220;gates&#8221; help RNNs <em>control</em> what data in a sequence to keep (ie remember), and what data to forget. This gets us one step closer to paying &#8220;attention&#8221;:</p><p>Ok, ok, but how do these fabled gates actually work?</p><p>Well, it depends, choose your fighter: Long Short-Term Memory (LSTM) networks or Gated Recurrent Units (GRUs). We&#8217;ll go with the more modern of the two, GRUs, introduced by Cho et al. in 2014.   </p><p>As mentioned, in &#8220;vanilla&#8221; feed-forward neural networks, a neuron is essentially an &#8220;activation function&#8221; (e.g., tanh&#8289;, sigmoid or ReLU) that receives a weighted sum and a bias as an input: &#963;(w1*a1 + w2*a2, w3*a2&#8230;.+ bias) and produces an &#8220;activation&#8221; that feeds into the next layer.</p><p></p><blockquote><p><strong>Technical Detail: </strong>Sigmoid, tanh, etc., functions are known as &#8220;squishification&#8221; functions as you can pass them an array of numbers (ie a word, ie a vector), and they will &#8220;squish&#8221; (ie map) these numbers to values between 0 and 1. This is helpful for probability calculus.<br><br>For example, if I pass [2.3, 5.1, 8.9] into the sigmoid activation function: &#8220;&#963;(2.3, 5.1, 8.9)&#8221; like so:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F2_F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F2_F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 424w, https://substackcdn.com/image/fetch/$s_!F2_F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 848w, https://substackcdn.com/image/fetch/$s_!F2_F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 1272w, https://substackcdn.com/image/fetch/$s_!F2_F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F2_F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png" width="588" height="342.0576923076923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:847,&quot;width&quot;:1456,&quot;resizeWidth&quot;:588,&quot;bytes&quot;:446810,&quot;alt&quot;:&quot;&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!F2_F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 424w, https://substackcdn.com/image/fetch/$s_!F2_F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 848w, https://substackcdn.com/image/fetch/$s_!F2_F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 1272w, https://substackcdn.com/image/fetch/$s_!F2_F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59d06e64-7e96-4fb0-8fe8-e7bb50ab4b58_1612x938.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It&#8217;ll return 2.3 = 0.9, 5.1 = 1, 8.9 = 1. Note, the&#8230; squishification! </p></blockquote><p> </p><p>RNNs introduce the concept of &#8220;time&#8221;, and hence, their activation functions are a little more complex: <em>&#963;(w1*a1 + w2*a2&#8230; + w1t-1*a1t-1 + w2t-1*a2t-1&#8230; + bias)</em>. </p><p>This notation is, frankly, wrong, but what &#8220;<em>w1t-1*a1t-1 + w2t-1*a2t-1</em>&#8221; is attempting to get across is that our activation functions in RNNs take into account both <em>an entirely new input </em>(e.g., a new word in a paragraph) as well as the activation produced by previous layers (known as the &#8220;hidden state&#8221;).</p><p>Unfortunately for us, GRU neurons (often referred to as &#8220;units&#8221; or &#8220;cells&#8221;) make the complexity of an RNN activation look rather&#8230; simple:<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!b62a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!b62a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png 424w, https://substackcdn.com/image/fetch/$s_!b62a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png 848w, https://substackcdn.com/image/fetch/$s_!b62a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png 1272w, https://substackcdn.com/image/fetch/$s_!b62a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!b62a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png" width="1175" height="607" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:607,&quot;width&quot;:1175,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53640,&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_!b62a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png 424w, https://substackcdn.com/image/fetch/$s_!b62a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png 848w, https://substackcdn.com/image/fetch/$s_!b62a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.png 1272w, https://substackcdn.com/image/fetch/$s_!b62a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01316c07-e91b-4eeb-8b28-ef7878acec8a_1175x607.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">Thanks to Michael Phi via Towards Data Science for the diagram inspiration <a href="https://towardsdatascience.com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21">here</a>.</figcaption></figure></div><p> </p><p>Don&#8217;t fret. Remember, the above is the equivalent of a neuron (ie a simple activation function) in a feed forward neural network. So, each layer of a GRU will consist of multiple of these units, that all connect to the next layer of the network.  </p><p>Note the presence of a &#8220;Reset Gate&#8221; and an &#8220;Update Gate&#8221; , as well as the specific insertion points of the sigmoid and tanh &#8220;squishification&#8221; functions. Let&#8217;s dig in via an analogy to root this complexity back to &#8220;real life&#8221;.</p><p>Think about the process of learning something new. You often have some base understanding of the topic (a hidden state, if you will), and then you&#8217;re gradually exposed to new information during your learning process. </p><p>Occasionally, your &#8220;hidden state&#8221; will be updated, as you realise that your prior understanding was perhaps off-kilter. Similarly, you may disregard some new information as it&#8217;s irrelevant or contradicts something you&#8217;ve learned that you consider to be true. GRU&#8217;s <em>data-controlling gates </em>are the machine equivalent.</p><p>Ok, back to our GRU:</p><p>Our <strong>Reset Gate </strong>is used to determine how much of the past (ie the &#8220;hidden state&#8221;) to forget. As shown in the diagram above, the current input value and the hidden state pass through the sigmoid function and produce a &#8220;reset gate value&#8221;. A value close to 0 means &#8220;forget the past&#8221;, a value close to 1 means &#8220;retain the past&#8221;.</p><p>Our <strong>Update Gate</strong> dictates how much of the remaining past information (ie the reset gate value) to keep vs. the new information to consider (e.g., a new word in a paragraph). The resulting (intermediary) value is known as the &#8220;candidate activation&#8221;.   </p><p>The final hidden state (or &#8220;activation&#8221; of the unit) is then calculated by combining the past hidden state with the new candidate activation. Et voil&#224;! Our unit is complete.</p><p>At this point I&#8217;ll (backward)pass<em> </em>(sorry!) this primer to you. What does all of this mean? Why do you think that &#8220;gating&#8221; helps deal with the vanishing gradient problem? Again, give it a go, it&#8217;ll help cement much of what you&#8217;ve read so far.</p><p>The truth is, gating helps in many ways. However, think about it, if gating reduces what our neural network needs to remember, then there are less available neurons (and hence, gradients) to perpetuate the vanishing gradient problem! </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Why Now = Your Personal Update Gate</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Hyena is defined as: a <strong>sub-quadratic </strong>drop-in replacement for <strong><s>attention</s></strong> constructed by interleaving <strong>implicitly parametrised</strong> <strong>long-convolutions </strong>and <strong><s>data-controlled</s> <s>gating</s></strong>. </p><p>Alright folks, it&#8217;s time for Transformers. If GRUs are capable of preserving long-term dependencies, why didn&#8217;t they unlock this current wave of AI mania? Well, there are a few reasons. </p><p>Firstly, GRUs (just like traditional RNNs) process data sequentially (duh, they&#8217;re used to process sequential data). The issue with this is that it makes &#8220;parallelisation&#8221; across time-steps difficult, leading to longer training times. What if we could process an entire body of text at once vs. doing so word-by-word?</p><p>Following closely in second, whilst GRUs are notably more performant than RNNs at recalling long-term dependencies, the Transformer&#8217;s &#8220;attention mechanism&#8221; represents relationships between inputs in a more complex and rich manner. </p><p>So, we know what &#8220;attention&#8221; means at a theoretical level, but how is this implemented technically and what is a &#8220;Transformer&#8221;, really?</p><p>Much like the <a href="https://www.europarl.europa.eu/ftu/pdf/en/FTU_1.1.3.pdf">European Union</a> (news to me), the Transformer consists of three core pillars: positional encodings, self-attention, and an overarching encoder-decoder structure. (We&#8217;ll tackle the first two)</p><p>Let&#8217;s start with positional encodings as they&#8217;re reasonably easy to get our heads around. Remember this dream?: &#8220;<em>what if we could process an entire body of text vs. doing so word-by-word?&#8221;, </em>well, it turns out we can do exactly this.</p><p>Instead of feeding a sentence (ie sequential data) word-by-word into a neural network to preserve its order, we can encode this positional information into the vector representation of each word.<br></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MhuJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MhuJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 424w, https://substackcdn.com/image/fetch/$s_!MhuJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 848w, https://substackcdn.com/image/fetch/$s_!MhuJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 1272w, https://substackcdn.com/image/fetch/$s_!MhuJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MhuJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png" width="905" height="215" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:215,&quot;width&quot;:905,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26542,&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_!MhuJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 424w, https://substackcdn.com/image/fetch/$s_!MhuJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 848w, https://substackcdn.com/image/fetch/$s_!MhuJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 1272w, https://substackcdn.com/image/fetch/$s_!MhuJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2f10c648-3f0c-4d90-8221-cca25c32617e_905x215.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Thanks to Ruth Sheridan&#8217;s Foundational Model <a href="https://arcxhived.substack.com/p/foundation-models">primer</a> for making this all click. Now there&#8217;s some &#8220;bias&#8221; for ye! IYKYK. </figcaption></figure></div><p></p><p>Due to their theoretical simplicity, positional encodings may seem trivial, but they&#8217;re a <em>game changer</em>. To contrast, within RNNs, each word is essentially given its own layer. This means that if we want to train on, say, adult fiction novels (70k - 120k avg. word count), our network would need, you guessed it, ~70-120k+ layers (!). Transformers dramatically reduce this &#8220;network depth&#8221;.</p><p>I personally don&#8217;t think positional encodings get enough publicity. Perhaps &#8220;Positional Encodings are All You Need&#8221; is missing the requisite alliteration? Anyhoo, how does the attention-grabbing, &#8220;attention mechanism&#8221;, work?</p><p>Let&#8217;s go back to my, incredibly subtle, call to action.. I mean.. example:<br></p><div class="preformatted-block" data-component-name="PreformattedTextBlockToDOM"><label class="hide-text" contenteditable="false">Text within this block will maintain its original spacing when published</label><pre class="text">                                       <em>[ hello, &#8212; please &#8212; subscribe &#8212; to &#8212; my &#8212; ]</em></pre></div><p><br>As a reminder, the idea behind attention is that certain words in a sentence have a greater &#8220;influence&#8221; on (or, relation to) a given word than others. </p><p>In our example, we said that &#8220;subscribe&#8221; (theoretically) would have a greater influence on &#8220;my&#8221; than &#8220;hello,&#8221; or &#8220;please&#8221; would.</p><p>Ok, so how is this &#8220;influence&#8221; actually calculated? Attention begins by deriving three vectors (ie points in space) for <em>each word</em> in a sentence. So, our sentence above would result in 15 vectors (hello x 3, please x 3,&#8230; etc) calculated for each &#8220;attention head&#8221; (ignore for now) within the Transformer. </p><p>Let&#8217;s stay as consistent as ever and use the word &#8220;subscribe&#8221; to walkthrough this vector math:</p><p><strong>Query Vector: </strong>This is a representation of what you&#8217;re looking for (e.g., something relevant to &#8220;subscribe&#8221;). It&#8217;s calculated by multiplying the original embedding of the word (subscribe=[.25, .17, .3]) by the query vector&#8217;s weight.</p><p></p><p></p><blockquote><p><strong>Key Point:</strong> Remember, this &#8220;weight&#8221; is often &#8220;initialised&#8221; with ~random values and learned over time through training. Just like any other neural network! </p></blockquote><p><strong><br>Key Vector: </strong>This is essentially an &#8220;index&#8221; or &#8220;tag&#8221; that makes a given word easier to categorise. It&#8217;s calculated by multiplying the original embedding of the word (subscribe=[.25, .17, .3]) by the given key vector&#8217;s weight. </p><p><strong>Value Vector: </strong>This is the actual &#8220;content&#8221; that you end up retrieving (ie a vector representation of &#8220;subscribe&#8221;). It&#8217;s calculated by multiplying the original embedding of the word, you guessed it, (subscribe=[.25, .17, .3]) by the given value vector&#8217;s weight. </p><p>Don&#8217;t worry readers (or,.. Alex), this math class is over shortly. Next, we take the query vector of one word (e.g., &#8220;subscribe&#8221;) and the key vectors of every word in the given sentence, including &#8220;subscribe&#8221; itself. </p><p>Through doing so, we calculate &#8220;attention scores&#8221; &#8212;  ie how relevant a list of words are to our query word (&#8220;subscribe&#8221;). Note in the example below that we&#8217;re doing matrix multiplication here to calculate these scores. The words on the left are the query vectors, and the words on the top are key vectors.  <br> </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Cwz0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Cwz0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png 424w, https://substackcdn.com/image/fetch/$s_!Cwz0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png 848w, https://substackcdn.com/image/fetch/$s_!Cwz0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png 1272w, https://substackcdn.com/image/fetch/$s_!Cwz0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Cwz0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png" width="1095" height="1020" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1020,&quot;width&quot;:1095,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53868,&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_!Cwz0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png 424w, https://substackcdn.com/image/fetch/$s_!Cwz0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png 848w, https://substackcdn.com/image/fetch/$s_!Cwz0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.png 1272w, https://substackcdn.com/image/fetch/$s_!Cwz0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3013313d-0879-44c4-98d4-9ee6f367fb6a_1095x1020.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>If we then repeat this process for every word in our sentence, well, our model has stored some form of &#8220;memory&#8221; or &#8220;state&#8221; associated with these words, without any need for the recurrence present in RNNs and GRUs. Without recurrence, the vanishing gradient problem literally dissipates!</p><p>We then run these scores through a &#8220;softmax&#8221; function (similar to our friend, the lowly sigmoid) to get these scores into a &#8220;normalised probability distribution&#8221;, also known as: between 0-1.  </p><p>&amp; finally, dear readers, we multiply each value from the softmax output with its corresponding value vector and sum them all up. This sum is the context-enriched output for a given set of words.</p><p>So, what&#8217;s hopefully clear is that Transformers&#8217; adulation is arguably just. Not only are they considerably more efficient to train (thanks positional encodings), but they also store long-term dependencies much more effectively than the next best thing!</p><p>Sound too good to be true?&#8230;    </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">[ hello, &#8212; please &#8212; subscribe &#8212; to &#8212; my &#8212; ]</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Hyena is defined as: a <strong>sub-quadratic </strong>drop-in replacement for <strong><s>attention</s></strong> constructed by interleaving <strong>implicitly parametrised</strong> <strong>long-convolutions </strong>and <strong><s>data-controlled gating</s></strong>. </p><p>For those of you left, nice work! I&#8217;m aware that calling this post a &#8220;lengther&#8221; (Irish colloquialism) would be an understatement. However, there&#8217;s plenty of historical context and other antecedents whose exposure/recall are typically assumed within these ML papers. A pity really! </p><p>Alas, I am here to spoil the party slightly. Whilst the attention mechanism is clearly a positive step-change, like many technical decisions, it isn&#8217;t immune to trade-offs. </p><p>Attention is <em>fundamentally</em> a quadratic operation. Think about it (&amp; revisit our matrix above), to calculate attention scores, you need to compare <em>n </em>number of words by <em>n </em>number of words (ie <em>n x n</em>).</p><p>Quadratic operations become inefficient as the size of the input (ie the context we provide a given LLM) grows, because the number of operations grow meaningfully:<br></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;1^{2} = 1, 2^{2} = 4, 3^{2} = 9, 4^{2} = 16,.... 99^{2} = 9801, 100^{2} = 10000&quot;,&quot;id&quot;:&quot;ZHLBSCSXYD&quot;}" data-component-name="LatexBlockToDOM"></div><p><br>This is (primarily) why ChatGPT et al., have context limits!</p><p>What if there was a way to resolve the quadratic nature of attention? (you may now strikethrough &#8220;<s>sub-quadratic</s>&#8221;). Can we remove this <em>n x n </em>dynamic whilst maintaining performance?   </p><p>The answer has been a partial &#8220;yes&#8221; for some time (thank you <a href="https://arxiv.org/abs/2212.14052">H3</a>, etc). However, Hyena, thanks to some lessons gleaned from signal processing, has made this confirmation rather resounding. </p><p>Quick level-setter: signal processing is a field of study that deals with the analysis, manipulation and, ultimately, interpretation, of &#8220;signals&#8221; (ie time or spatial-varying data like audio). Hmm. This sure sounds akin to sequential data?</p><p>Within signal processing, &#8220;<a href="https://www.youtube.com/watch?v=KuXjwB4LzSA">convolutions</a>&#8221; (a mathematical operation) are used to calculate how one signal (e.g. your voice) is modified by another signal or system (e.g. a room). Through leveraging convolutions, we can precisely enhance or attenuate a specific signal by adjusting its &#8220;filters&#8221; accordingly.</p><p><em>Hmm x 2</em>. &#8220;Enhance or attenuate&#8221; &#8212; this also sounds a little similar to what the attention mechanism does in Transformers, or perhaps &#8220;gates&#8221; in GRUs? Both mechanisms <em>amplify</em> or <em>reduce </em>certain inputs (ie data). </p><p>So, perhaps these &#8220;filters&#8221; can similarly preserve long-range dependencies? </p><p>The truth is, they&#8217;ve already been doing so (albeit inadequately) for some time. I suspect those of you that aren&#8217;t entirely new to deep learning have been graced by &#8220;CNNs&#8221; or <em>Convolutional Neural Networks</em>?</p><p>Well, within these networks, it&#8217;s these &#8220;filters&#8221; that are tweaked and learned over time. Much like our weights and bias within a traditional neuron! A filter (aka &#8220;kernel&#8221; or &#8220;mask&#8221;) in a CNN is typically a matrix like so:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t2gC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t2gC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png 424w, https://substackcdn.com/image/fetch/$s_!t2gC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png 848w, https://substackcdn.com/image/fetch/$s_!t2gC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png 1272w, https://substackcdn.com/image/fetch/$s_!t2gC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t2gC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png" width="400" height="401.44404332129966" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:556,&quot;width&quot;:554,&quot;resizeWidth&quot;:400,&quot;bytes&quot;:24436,&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_!t2gC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png 424w, https://substackcdn.com/image/fetch/$s_!t2gC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png 848w, https://substackcdn.com/image/fetch/$s_!t2gC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.png 1272w, https://substackcdn.com/image/fetch/$s_!t2gC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92fcb0af-2541-40ca-b21b-8be1b6299bf5_554x556.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">A &#8220;short&#8221; 3x3 filter - note that an input image itself may be much &#8220;longer&#8221; a la 28x28 pixels</figcaption></figure></div><p>Specifically, &#8220;convolutional layers&#8221; (which contain many filters) are often used at the beginning of computer vision tasks to extract key &#8220;features&#8221; of an image. A <em>very </em>high-level example of an extractable feature may be something like rounded corners. </p><p>So, if my CNN has been sufficiently trained (and hence, had its filters tweaked) to identify rounded corners in an image, when it ingests an image whose data overlaps with the above matrix, our model may infer that this image has a rounded corner. A match! Nice.<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uWY4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uWY4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png 424w, https://substackcdn.com/image/fetch/$s_!uWY4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png 848w, https://substackcdn.com/image/fetch/$s_!uWY4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png 1272w, https://substackcdn.com/image/fetch/$s_!uWY4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uWY4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png" width="458" height="459.67000911577026" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1101,&quot;width&quot;:1097,&quot;resizeWidth&quot;:458,&quot;bytes&quot;:81209,&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_!uWY4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png 424w, https://substackcdn.com/image/fetch/$s_!uWY4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png 848w, https://substackcdn.com/image/fetch/$s_!uWY4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.png 1272w, https://substackcdn.com/image/fetch/$s_!uWY4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f81a81e-0b19-4303-8015-b9f9154fe130_1097x1101.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">An image - each numerical value may theoretically equal the value of a pixel (point in space x colour)</figcaption></figure></div><p></p><p>Much like its scavenging counterpart, the Hyena Operator takes what&#8217;s good from the &#8220;bone&#8221; of the CNN. However, it then goes one step further: </p><p>Instead of relying on the &#8220;short&#8221; filters (e.g., a 3x3 matrix) present in CNNs, Hyena leverages &#8220;long&#8221; convolutions (ie filters that span the entire length of the input sequence). This means that the entire input is a feature! Meaning that each output element depends on <em>all inputs</em>, thus capturing the &#8220;global context&#8221; of the input image, sentence, etc.  </p><p>Hyena is defined as: a <strong><s>sub-quadratic</s> </strong>drop-in replacement for <strong><s>attention</s></strong> constructed by interleaving <strong>implicitly <s>parametrised</s></strong><s> </s><strong><s>long-convolutions</s> </strong>and <strong><s>data-controlled gating</s></strong>.  </p><p>Fancy striking through &#8220;implicitly&#8221; also? Cool, implicitly just means that these filters are learned (much like we&#8217;ve already learned ourselves) vs. hard-coded. Simple!</p><p>Hyena is defined as: a <strong><s>sub-quadratic</s> </strong>drop-in replacement for <strong><s>attention</s></strong> constructed by interleaving <strong><s>implicitly</s> <s>parametrised</s></strong><s> </s><strong><s>long-convolutions</s> </strong>and <strong><s>data-controlled gating</s></strong>.</p><p>Ok, cool, definition complete, but how does Hyena&#8217;s combination of &#8220;long-convolutions&#8221; and &#8220;data-controlled gating&#8221; equate to computational complexity that is <em>O(n log n)</em>? Or, &#8220;sub-quadratic&#8221;.</p><p>Well, put simply, there&#8217;s no <em>n x n </em>calculation present in Hyena. Long-convolutions enable the learning of long-range dependencies (without a <em>n x n</em> attention matrix), and data-controlled gating, much like we&#8217;ve seen in GRUs, filters out unnecessary data (and hence, computation).</p><p><em><s>Post-Transformers - Hyena Hierarchy</s></em> - c&#8217;est fini!</p><div><hr></div><p><em>If you&#8217;ve made it this far, thank you (&amp; fair play!). If you&#8217;ve learned something along the way, I&#8217;d love it if you share this post with a friend or two. I&#8217;m pretty close to an exciting subscriber milestone so it&#8217;d help a tonne!</em> </p><p><em>As always, I&#8217;m at alex@tapestry.vc - always down to say hello! If you&#8217;re wondering where to go next, check out my posts on <a href="https://whynowtech.substack.com/p/nix">Nix</a>, <a href="https://whynowtech.substack.com/p/zig">Zig</a>, <a href="https://whynowtech.substack.com/p/webgpu">WebGPU</a> or <a href="https://whynowtech.substack.com/p/bonus-remaking-pokemon-yellow-in">Building Pokemon Yellow in Godot</a> (personal fave).</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><em>please = s(u(b(s(c(r(i(b(e(!)))))))))</em> </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[A Frontend IDE ]]></title><description><![CDATA[UX/UI designers and frontend engineers have been converging for some time.]]></description><link>https://whynowtech.substack.com/p/a-frontend-ide</link><guid isPermaLink="false">https://whynowtech.substack.com/p/a-frontend-ide</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Wed, 14 Jun 2023 17:20:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F6ea113dc-4511-4cda-914c-0c05af9726a5_210x210.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>UX/UI designers and frontend engineers have been converging for some time. I&#8217;m undecided if &#8220;design engineer&#8221; is apt, but if we look at my friend <a href="https://twitter.com/NevFlynn">Nev&#8217;s</a> work (&amp; LinkedIn bio!) at <a href="https://evervault.com/">Evervault</a> it&#8217;s clear that designers can write some pretty gnarly JS.<br><br>Clearly, this latest wave in generative AI is abrupt-enough of a change to expedite this trend. The question then becomes, does this new class of engineer have the right integrated development environment? <br><br>Currently, as far as I know, to design a site like Evervault&#8217;s the core tooling you need is: an IDE, Figma and Blender/Spline. Perhaps something on the animation side also to build advanced SVG path animations, etc. Should this all be bundled together?<br><br>Cue: &#8220;Framer does a really good job&#8230;&#8221;. Yes, 100%. I love Framer. However, I also love specific animation libraries (yes, beyond Framer motion), three.js, and dare I say it.. writing code.</p><p>Taking the above into account, what would a, from the ground-up, &#8220;frontend IDE&#8221; look like? <br><br>This is my first Substack &#8220;thread&#8221; so.. um.. discuss!  </p>]]></content:encoded></item><item><title><![CDATA[Zig]]></title><description><![CDATA[Efficient and portable as C, without the "footguns"]]></description><link>https://whynowtech.substack.com/p/zig</link><guid isPermaLink="false">https://whynowtech.substack.com/p/zig</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Mon, 12 Jun 2023 16:36:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!FVyf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>Welcome to new subs + thanks a million for the <a href="https://whynowtech.substack.com/p/bonus-remaking-pokemon-yellow-in">Godot</a> love! This thing has grown a whole lot faster than my inner-pessimist could have imagined. So, grazie!</em></p><p><em><strong>If you enjoy these primers, I&#8217;d appreciate it if you favourite this post&#8217;s <a href="https://twitter.com/alex__mackenzie">tweet</a> to help spread the good (?) word of Why Now!</strong></em></p><p><em>As always, I&#8217;m at alex@tapestry.vc should you ever wish to say hello. If you are building with Zig, I most definitely want to chat.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FVyf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FVyf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!FVyf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!FVyf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!FVyf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FVyf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:130557,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FVyf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!FVyf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!FVyf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!FVyf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa1cf4bd4-2aea-4685-be9d-b08ff531b012_1920x1080.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></figure></div><p>Not every technology is capable of direct value capture. This can be perilous as an infra investor, as it&#8217;s easy to become enamoured by something that&#8217;s innovative, yet devoid of a business model or meaningful market. Guilty. </p><p>Programming languages are a good example here. How Rust handles concurrency is a thing of beauty, <a href="https://www.roc-lang.org/">Roc&#8217;s</a> VM-less memory allocation is pretty cool.. and, well, there&#8217;s a lot to like about <a href="https://ziglang.org/">Zig</a>. However, these languages aren&#8217;t licensed out, their value capture certainly isn&#8217;t tied to usage/utility. </p><p>What helps me sleep at night however is that these technologies (think languages, runtimes, protocols, etc) can serve as proxies for sophisticated &amp; opinionated technologists. Dissenters capable of <em><a href="https://whynowtech.substack.com/p/deno#:~:text=The%20theoretical%20physicist%2C%20Wolfgang%20Pauli%2C%20is%20widely%20attributed%20for%20the%20counter%2Dintuitive%20critique%3A%20%E2%80%9Cit%E2%80%99s%20not%20even%20wrong%E2%80%9D.">being wrong</a></em>. </p><p>Now this is something that history would tell me capital is worth putting towards.</p><p>Take Zig for example. <a href="https://bun.sh/">Bun</a> is outpacing Node.js and its anagrammatic counterpart, Deno. How so? Well, Bun does a lot of things well, but it does tout Zig&#8217;s low-level control of memory and lack of hidden control flow (<em>so good!</em>) as a key unlock. </p><p>Continuing down this proxy, we find Stephen Gutekanst / <a href="https://machengine.org/#early-stages">Mach Engine</a> working 24/7 on a game engine to help &#8220;upend the gaming industry&#8221;. Building a game engine ~<em>from scratch</em> is no small feat. </p><p>++ finally, we have <a href="https://tigerbeetle.com/">TigerBeetle</a>. Again, one doesn&#8217;t simply build a financial database from the ground up over a leisurely weekend. Zig has served as a beacon, attracting those who&#8217;re thinking orthogonally. I&#8217;m fond of folk like this.</p><p>As you may have guessed from, I don&#8217;t know, the title (!) we&#8217;re going to dig into Zig.</p><p>Selfishly, I want to truly get my head around why companies are opting to build with this nascent language as well as what we should expect next. I figured I&#8217;d bring you all along for the ride. </p><p><strong>If you are building with Zig, I&#8217;d love to say hello! alex@tapestry.vc</strong></p><p><a href="https://github.com/sponsors/ziglang">Finally, I&#8217;d ask that, if possible, you consider supporting the Zig Software Foundation.</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for my next primer, on TigerBeetle!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p> Zig is many <a href="https://mitchellh.com/zig/tokenizer">[1]</a><a href="https://mitchellh.com/zig/parser">[2]</a><a href="https://mitchellh.com/zig/astgen">[3]</a> things <a href="https://mitchellh.com/zig/sema">[4]</a><a href="https://mitchellh.com/zig/build-internals">[5]</a> but at its core it&#8217;s: </p><ol><li><p>A general-purpose programming language (think Python or JavaScript).</p></li><li><p>A &#8220;toolchain&#8221;.  </p></li></ol><div><hr></div><p>The programming language part here is familiar, and hence, easy to grok. However, it&#8217;s worth lingering on. My favourite quality of Zig&#8217;s is its <em>simplicity</em>. What does this mean?</p><p>Well, firstly, the language is <em>tiny</em>. </p><p>It&#8217;s specified with a <a href="https://ziglang.org/documentation/master/#Grammar">500-line PEG grammar file</a>. For context, a PEG (parsing expression grammar) file is typically used to define the structure and syntax of a programming language.</p><p>The tl;dr on this benefit is that a &#8220;small&#8221; language ultimately means that you have less language-specific keywords, etc., to remember. Hence, the language is &#8220;simple&#8221;. </p><p><em>** As someone that somehow still struggles to recall git flags, I&#8217;m --happy about this! **</em></p><p>Less keywords also means that there&#8217;s ideally &#8220;<em>only one obvious way to do things</em>.&#8221; Why is this good? Well, it becomes much easier to read your/someone else&#8217;s code when you know that a specific keyword is typically used for a handful (vs. infinite) number of things. <br></p><blockquote><p><strong>Fun Fact:</strong> Zig's developers took this mandate so much to heart that for a time, <a href="https://github.com/ziglang/zig/issues/8292">Zig had no for loop</a>, which was deemed an unnecessary syntactic elaboration upon the already adequate <code>while</code> loop. &#8220;What you do is who you are&#8221;. </p></blockquote><p><br>This goal stands in stark contrast with decisions made within languages like Python, where I&#8217;ve truly lost track of the number of keywords that essentially say: &#8220;if this happens then do that&#8221;. Sorry, I&#8217;m ranting. </p><p>Back to Zig. The language doesn&#8217;t stop here though, oh no. Zig also has &#8220;no hidden control flow&#8221;. This essentially means that each line-of-code written in Zig executes sequentially, as you would expect:<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KGhM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KGhM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png 424w, https://substackcdn.com/image/fetch/$s_!KGhM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png 848w, https://substackcdn.com/image/fetch/$s_!KGhM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png 1272w, https://substackcdn.com/image/fetch/$s_!KGhM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KGhM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png" width="1084" height="496" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:496,&quot;width&quot;:1084,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:188588,&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_!KGhM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png 424w, https://substackcdn.com/image/fetch/$s_!KGhM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png 848w, https://substackcdn.com/image/fetch/$s_!KGhM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.png 1272w, https://substackcdn.com/image/fetch/$s_!KGhM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2dbb1e2b-8626-44d7-95e5-b12a80c900c8_1084x496.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><br>If you haven&#8217;t written code before this is likely confusing: <em>doesn&#8217;t all code execute.. line-by-line (ie sequentially)? </em>Nope. Oftentimes languages (e.g., JavaScript) will take ~helpful but &#8220;<strong>hidden&#8221;</strong> steps for the developer to ~fix/improve the execution order (ie &#8220;<strong>control flow</strong>&#8221;) of their code.<br> </p><blockquote><p><strong>Technical Detail:</strong> Check out variable/function &#8220;<a href="https://www.digitalocean.com/community/tutorials/understanding-hoisting-in-javascript">hoisting</a>&#8221; in JavaScript as an example of such hidden magic. </p></blockquote><p><br>This action is often helpful, as intended. However, because it&#8217;s hidden from the developer, it can make their code more difficult to reason about (especially for other developers). </p><p>Make sure this point clicks as it&#8217;s important. Think about it, a developer could forget about the hidden control flow rules of a given language; all of a sudden, their code isn&#8217;t executing sequentially as expected? This happens, often in subtle ways, and is confusing for all involved.  </p><p>As Zig eloquently puts it, you should <em>&#8220;focus on debugging your application, not your programming language knowledge&#8221;. </em></p><p><a href="https://bun.sh/">Bun</a> provides an equally glowing endorsement: <em>&#8220;low-level control over memory and lack of hidden control flow makes it much <strong>simpler</strong> to write fast software.&#8221;</em> </p><p>Alas, we have introduced a new value prop here: &#8220;Low-level control over memory&#8221;. Que?</p><p>Much like <a href="https://genius.com/Fall-out-boy-thnks-fr-th-mmrs-lyrics">Fall Out Boy</a> (sorry), our computers have &#8220;memory&#8221; or &#8220;<a href="https://genius.com/Fall-out-boy-thnks-fr-th-mmrs-lyrics">mmrs</a>&#8221; (sorry again). ie spaces (e.g., RAM) within the system where they store data or instructions that will ultimately be used/manipulated again. </p><p>For example, in my JavaScript program: `example.js` I might create a variable: `let age = 28`. JavaScript will then pull some Houdini-work once more and <em>dynamically</em> allocate enough space in memory at &#8220;<a href="https://whynowtech.substack.com/p/deno#:~:text=A%20%E2%80%9Cruntime%E2%80%9D%20is%20a%20piece%20of%20software%20that%20helps%20developers%20create%2C%20compile%20and%20execute%20programs.%20To%20grossly%20oversimplify%2C%20execute%20%3D%20make%20a%20program%20do%20what%20it%E2%80%99s%20supposed%20to%20do.">runtime</a>&#8221; to store the variable `age` for me. Helpful.<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_uM-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_uM-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png 424w, https://substackcdn.com/image/fetch/$s_!_uM-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png 848w, https://substackcdn.com/image/fetch/$s_!_uM-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png 1272w, https://substackcdn.com/image/fetch/$s_!_uM-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_uM-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png" width="1040" height="368" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:368,&quot;width&quot;:1040,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:127534,&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_!_uM-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png 424w, https://substackcdn.com/image/fetch/$s_!_uM-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png 848w, https://substackcdn.com/image/fetch/$s_!_uM-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.png 1272w, https://substackcdn.com/image/fetch/$s_!_uM-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff080b2c1-7d44-4b80-a310-33ea420f2d23_1040x368.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">JavaScript is recognising on its own that age is an integer and allocating memory accordingly.</figcaption></figure></div><p><br>Zig, is less.. presumptuous. Within Zig we have to specify what <em>type</em> our variable is, which reveals a tad more information about how much memory our variable requires.</p><p><em>** If you want to visit / revisit &#8220;types&#8221; check out my <a href="https://whynowtech.substack.com/p/deno#:~:text=In%20programming%20languages%2C%20%E2%80%9Ctypes%E2%80%9D%20are%20a%20set%20of%20categories%20that%20describe%20what%20a%20value%20in%20a%20program%20is%20(ie%20is%20it%20a%20number%2C%20a%20string%2C%20a%20boolean%2C%20etc.)%2C%20and%20as%20a%20result%2C%20what%20operations%20can%20be%20taken%20on%20the%20value.">primer</a> on Deno (+ TypeScript)! **<br></em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G3PO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G3PO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png 424w, https://substackcdn.com/image/fetch/$s_!G3PO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png 848w, https://substackcdn.com/image/fetch/$s_!G3PO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png 1272w, https://substackcdn.com/image/fetch/$s_!G3PO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G3PO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png" width="1040" height="496" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:496,&quot;width&quot;:1040,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:178141,&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_!G3PO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png 424w, https://substackcdn.com/image/fetch/$s_!G3PO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png 848w, https://substackcdn.com/image/fetch/$s_!G3PO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.png 1272w, https://substackcdn.com/image/fetch/$s_!G3PO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8722d2c-123c-497b-8c72-5b0f9cb83902_1040x496.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">We must explicitly state how much memory we want a variable to take up. Hence the &#8220;i32&#8221;.</figcaption></figure></div><p><br>Zig doesn&#8217;t stop here though, defining your types &#8220;statically&#8221; is the easy part. </p><p>Zig, much like C and C++, enables developers to allocate memory (remember, a space) <em>manually. </em>This means that Zig developers can ~precisely state how much memory they require for a given variable, function, etc., as well as when this memory should be <em>freed, </em>and hence, used elsewhere.</p><p>Again, to make the comparison to <a href="https://en.wikipedia.org/wiki/Brendan_Eich#:~:text=Brendan%20Eich%20(/%CB%88a%C9%AAk/%3B%20born%20July%204%2C%201961)%5B1%5D%20is%20an%20American%20computer%20programmer%20and%20technology%20executive.%20He%20created%20the%20JavaScript%20programming%20language">Brendan Eich&#8217;s</a> darling &#8212; JavaScript handles this freeing of memory automatically. This process is known as &#8220;garbage collection&#8221;.<br></p><blockquote><p><strong>Technical Detail:</strong> Unlike C and C++, which use the `malloc` keyword, Zig doesn&#8217;t expose memory allocation directly in the language&#8217;s syntax. </p><p>Instead, memory access is exposed via Zig&#8217;s &#8220;standard library&#8221;. <br><br>A standard library is a set of pre-installed functions/objects that are ready to be used with a given language. For example, Python&#8217;s standard library comes with the `datetime` object. </p><p>This, again, makes memory allocation in Zig more explicit / clear. </p></blockquote><p><br>At this point you&#8217;re likely thinking, &#8220;so what&#8221;. Fair. What&#8217;s important to know &#8212; and what relates back to Bun&#8217;s proclamation in our intro &#8212; is that this granular control of memory leads to performance gains. Why?</p><p>Well, there are a few reasons. I&#8217;ll point-er (sorry) out two:</p><p><strong>1. Fragmentation: </strong>As memory is allocated and deallocated dynamically, free memory blocks become scattered across the &#8220;heap&#8221; (place especially for dynamic memory). This can result in fragmented memory, where there are small gaps between allocated blocks. </p><p>I&#8217;ve <a href="https://excalidraw.com/">&#8220;drawn&#8221;</a> a diagram that hopefully depicts this issue better than the wall of text above does. The main point being that these fragments, because they&#8217;re small, end up being a literal waste of space. (harsh, I know)<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pgjC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pgjC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png 424w, https://substackcdn.com/image/fetch/$s_!pgjC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png 848w, https://substackcdn.com/image/fetch/$s_!pgjC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png 1272w, https://substackcdn.com/image/fetch/$s_!pgjC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pgjC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png" width="1232" height="632" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:632,&quot;width&quot;:1232,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:195458,&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_!pgjC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png 424w, https://substackcdn.com/image/fetch/$s_!pgjC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png 848w, https://substackcdn.com/image/fetch/$s_!pgjC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.png 1272w, https://substackcdn.com/image/fetch/$s_!pgjC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17d8ddb0-7bd9-49c1-9b41-520f34fb83f8_1232x632.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><br>2. Garbage Collection: </strong>Yep, y&#8217;boy garbage collection (GC) packs a punch. GC  introduces additional overhead. Why? Well, because it&#8217;s ultimately another &#8220;program&#8221; running in the background of your own.</p><p>Andrew Kelley, the creator of Zig, <a href="https://www.youtube.com/watch?v=Gv2I7qTux7g">goes</a> as far as saying that GC can result in <em>&#8220;stop the world latency glitches&#8221;</em>. When it comes to building critical systems (think aviation software), &#8220;latency&#8221; doesn&#8217;t cut it. </p><p>GC can also result in &#8220;non-deterministic&#8221; memory deallocation. ie, it may ultimately free memory that you would have ideally still had allocated. This is another example of a &#8220;hidden&#8221; action that other languages take. </p><p>To reiterate, whilst potentially <a href="https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/#:~:text=Microsoft%3A%2070%20percent%20of%20all%20security%20bugs%20are%20memory%20safety%20issues">perilous</a>, software written in C, C++, Zig, etc., <em>can be</em> more performant than software written in dynamically allocated memory (DAM.. Daniel) languages a la Python or JavaScript.</p><p>Once again, Zig&#8217;s explicitness (in this case, explicit memory allocation) is what makes it <em>simple</em>. You, and your rag-and-tag crew of developers, don&#8217;t have to figure out how memory&#8217;s allocated/freed in your application, you literally state this in your code.<br><br><em>** Did I mention the word explicit? **</em></p><p>As hard is it may be to believe, Zig does even more to foster &#8220;simple&#8221; codebases such as omitting a &#8220;preprocessor&#8221; and &#8220;macros&#8221;. Don&#8217;t worry, we&#8217;ll get into what these terms mean.  </p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/zig?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">You know what&#8217;s also simple? Telling your friends about this post / Why Now.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/zig?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://whynowtech.substack.com/p/zig?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><p> <em>** Ok, take a sip of water, go get some sunshine etc., we&#8217;re onto Zig&#8217;s &#8220;toolchain&#8221; **</em></p><p></p><div><hr></div><p>The meaning of &#8220;toolchain&#8221; is a little more difficult to accurately scope. However, the word typically means a set of utilities: <strong>libraries</strong>, <strong>compilers</strong>, <strong>build tools</strong>, etc., that the language, or users of the language, can leverage.</p><ol><li><p><strong>Libraries</strong> = code that someone else has written and packaged which can now be used by others to achieve a specific task. E.g., Rust&#8217;s <a href="https://www.pola.rs/">Pola.rs</a> library for data manipulation. </p></li><li><p><strong>Compilers</strong> = take your high-level code and convert it to &#8220;machine code&#8221; (1s and 0s) that corresponds to a specific <a href="https://whynowtech.substack.com/p/ebpf#:~:text=Native%20Code%3A%20Machine%20code.%20More%20technically%20known%20as%20a%20CPU%E2%80%99s%20Instruction%20Set%20Architecture%20(e.g.%2C%20x86%20or%20ARM).">instruction set</a>. Do some other helpful things like optimising your code (e.g., removing &#8220;dead code&#8221;).</p></li><li><p><strong>Build Tools</strong> = a build tool manages the entire build process, which includes compilation but also includes dependency management, testing, packaging, etc. I wrote about &#8220;building&#8221; software in detail on my Nix <a href="https://whynowtech.substack.com/p/nix">primer</a>.  </p></li></ol><p>We can use Zig&#8217;s stated goals (&#8220;maintaining <strong>robust</strong>, <strong>optimal</strong> and <strong>reusable</strong> software&#8221;) to fine-tune our definition.</p><ol><li><p><strong>Robust </strong>= software written in Zig works consistently, even during edge-cases. </p></li><li><p><strong>Optimal</strong> = software written in Zig can be.. optimised.. for a specific task.   </p></li><li><p><strong>Reusable</strong> = software written in Zig is simple, scalable &amp; portable.  </p></li></ol><p>With these goals in mind, <em>I consider </em>(go easy HN!) the Zig toolchain&#8217;s most notable features to be the following two:</p><ol><li><p>Zig&#8217;s &#8220;<strong>Comptime</strong>&#8221;.</p></li><li><p>Zig&#8217;s 4 <strong>build systems</strong>. </p></li></ol><div><hr></div><p>Ok, I&#8217;m done writing in lists of twos &amp; threes, I promise. Let&#8217;s delve into Zig&#8217;s &#8220;Comptime&#8221;.</p><p>Zig touts its Comptime as <em>&#8220;A fresh approach to <strong>metaprogramming</strong> based on <strong>compile-time</strong> code execution and <strong>lazy evaluation</strong>.&#8221; </em>Let&#8217;s unpack each word emphasised as per. First, <em>compile-time</em>.  </p><p>Software has a &#8220;lifecycle&#8221; that ultimately results in said software being executed (ie running on a computer): </p><p>Developers write code (think Python), &#8220;compile&#8221; this code, &#8220;link&#8221;<em> </em>each compiled file generated (called an &#8220;object file&#8221;) into a final &#8220;executable&#8221; and then &#8220;run&#8221; (ie execute) this.. um.. executable.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MMIc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MMIc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png 424w, https://substackcdn.com/image/fetch/$s_!MMIc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png 848w, https://substackcdn.com/image/fetch/$s_!MMIc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png 1272w, https://substackcdn.com/image/fetch/$s_!MMIc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MMIc!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png" width="1066" height="460.51785714285717" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:629,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1066,&quot;bytes&quot;:70624,&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-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MMIc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png 424w, https://substackcdn.com/image/fetch/$s_!MMIc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png 848w, https://substackcdn.com/image/fetch/$s_!MMIc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.png 1272w, https://substackcdn.com/image/fetch/$s_!MMIc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ca635a7-e66d-414d-936a-264d8ba60bcb_2888x1248.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>Programming languages are typically evaluated at <em>either </em>compile-time (e.g., TypeScript) or runtime (JavaScript). &#8220;Evaluation&#8221; essentially means checking for errors, determining the &#8220;type&#8221; of a given variable, etc., all with the aim of ultimately executing a program. </p><p>Like any technical decision, there isn&#8217;t an objectively &#8220;correct&#8221; way to evaluate a program. Rather, there are trade-offs.</p><p>For example, if you evaluate a language&#8217;s &#8220;types&#8221; at compile-time, then you&#8217;ll pick-up the incorrect usage of a &#8220;string&#8221; in a function that expects an &#8220;integer&#8221; <em>before</em> you compile said language and run it somewhere. Thus picking up a &#8220;bug&#8221; before your software is deployed. <em>Phew</em>.</p><p>The drawback of this compile-time eval is that developers have to specify the exact type of data they expect their function to receive. This can get rather tricky. Why? Well, end-users of software are unpredictable, they may end up inserting valid data types (e.g., an integer in a &#8220;<a href="https://www.washingtonpost.com/technology/2020/05/08/musk-grimes-baby-name/#:~:text=new%20baby%20boy%2C-,X%20%C3%86%20A%2D12,-.">first name</a>&#8221; field on a form) that you may not expect.  </p><p>Zig takes a more.. democratic, approach. The language enables developers to <em>explicitly</em> state which blocks of their code they&#8217;d like &#8220;evaluated&#8221; at compile-time vs. runtime. This is handled via Zig&#8217;s `comptime` keyword:<br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wCbh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wCbh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png 424w, https://substackcdn.com/image/fetch/$s_!wCbh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png 848w, https://substackcdn.com/image/fetch/$s_!wCbh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png 1272w, https://substackcdn.com/image/fetch/$s_!wCbh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wCbh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png" width="1040" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1040,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:290860,&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_!wCbh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png 424w, https://substackcdn.com/image/fetch/$s_!wCbh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png 848w, https://substackcdn.com/image/fetch/$s_!wCbh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.png 1272w, https://substackcdn.com/image/fetch/$s_!wCbh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41e5bef7-4d39-4bf6-9d33-e148856e79be_1040x804.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><br>Taking all that we now know about Zig, we can assume that the primary goal of this explicit statement of compile-time vs. runtime evaluation is.. you guessed it, <em>explicitness</em>. </p><p>A developer reading your Zig code doesn&#8217;t have to identify/recall what&#8217;s being evaluated at compile-time, you literally tell them. Much like Zig&#8217;s control flow, nothing is &#8220;hidden&#8221; from the developer. </p><p>Ok, cool, we like explicitness. However, I want to also point out that Comptime reiterates Zig&#8217;s ability to be fine-tuned for performance. </p><p>For example, if we offload type inference to the <em>developer</em> who compiles their software, then the <em>end-user </em>(think a general &#8220;consumer&#8221;)<em> </em>doesn&#8217;t have to handle type inference on their own machine at runtime. Nice.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/zig?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">Given we like explicitness, I&#8217;ll be explicit. Tell your friends etc.!</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/zig?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://whynowtech.substack.com/p/zig?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p>Right, so we know what evaluation is and when it happens (compile-time / runtime). What&#8217;s &#8220;lazy&#8221; evaluation?</p><p>Well, thankfully, it&#8217;s rather self-explanatory. Lazy evaluation, much like a &#8220;lazy person&#8221;, isn&#8217;t proactive, it only completes a task at the last-minute, when it must.   </p><p>I&#8217;ll make this more concrete with some (simple!) Zig code which we&#8217;ll build on.<br> </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7nDa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7nDa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png 424w, https://substackcdn.com/image/fetch/$s_!7nDa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png 848w, https://substackcdn.com/image/fetch/$s_!7nDa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png 1272w, https://substackcdn.com/image/fetch/$s_!7nDa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7nDa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png" width="1102" height="534" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:534,&quot;width&quot;:1102,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:219768,&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_!7nDa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png 424w, https://substackcdn.com/image/fetch/$s_!7nDa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png 848w, https://substackcdn.com/image/fetch/$s_!7nDa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.png 1272w, https://substackcdn.com/image/fetch/$s_!7nDa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa8e4ad41-77c4-4c82-9402-965106d77b8a_1102x534.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">Note that we&#8217;re using &#8220;string literals&#8221; here as a data type.</figcaption></figure></div><p><br>If we were to <em>lazily evaluate </em>this code, we would only check/determine the values of the variables: <code>first_name</code> (&#8220;Alex&#8221;) and <code>second_name </code>(&#8220;Mackenzie&#8221;), when we need them. In this case, we need these values to complete the <code>first_name ++ second_name</code> operation.</p><p>Why is lazy evaluation helpful you ask? Well, it means you&#8217;re not doing any heavy-lifting before you have to, which ultimately results in more-efficient resource allocation. </p><p>Why calculate the value of an expression if you&#8217;re only <em>maybe </em>(e.g., in the context of conditional logic) going to use it later? Smart. </p><p>This said, whilst Zig makes this lazy eval.. explicit.. I do personally feel that lazy evaluation goes against Zig&#8217;s simplicity / feels a little &#8220;hidden&#8221;. This is a primer though, so let&#8217;s leave my judgement to the side.</p><div><hr></div><p>Well, this is a &#8220;lengther&#8221;. Sorry, but programming languages are very much the aggregation of minute technical decisions that, in aggregate, support a handful of objectives. If you want to grok a language, you&#8217;ve got to appreciate its nuances. </p><p>Next, &#8220;Metaprogramming&#8221;. Remember our brief mention of &#8220;preprocessors&#8221; and &#8220;macros&#8221;? They&#8217;re back. Kinda. </p><p>Metaprogramming is common in systems-level programming languages like C, C++, Rust. It&#8217;s what you likely expect &#8212; a program, &#8220;programming&#8221; itself. <em>Woah, meta</em>.        </p><p>In practice, metaprogramming involves leveraging compile-time information (e.g., type declarations like: <code>var age: i32 = 28;</code>) to manipulate (e.g., edit/generate code) your program in some way.</p><p>For example, with this &#8220;type information&#8221; our program could <em>automatically</em> edit our variable <code>age</code>&#8217;s data type to be &#8220;i8&#8221; vs. &#8220;i32&#8221;. i8 is a smaller data type, and hence, takes up less memory. Thus, through metaprogramming, we have optimised our Zig code at compile-time. <em>C'est tr&#232;s cool!<br></em></p><blockquote><p><strong>Technical Detail:</strong> In C/C++ metaprogramming is handled by a &#8220;preprocessor&#8221; program that uses &#8220;macros&#8221; (ie specific keywords like: <code>#define</code>).<br> <br>Without getting unnecessarily into the weeds, these macros are complex/error-prone; so much so that they&#8217;re considered by some to be a &#8220;separate programming language&#8221; beyond C/C++.<br><br>Whereas Zig treats metaprogramming as a &#8220;first-class citizen&#8221;, and hence, tightly integrates the process with the rest of its &#8220;toolchain&#8221; (via Comptime).  </p></blockquote><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/zig?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">Share so that other people share? <em>Woah, meta.</em></p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/zig?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://whynowtech.substack.com/p/zig?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><p>Alright, we&#8217;re nearly wrapped up here with Zig. For those of you still here, nice job, this isn&#8217;t an easy read by any means. It certainly wasn&#8217;t a walk in the park for my ghost-writer to draft! (<em>joke</em>).</p><p>As mentioned, Zig is&#8230; supple. It has 4 &#8220;build modes&#8221;. Again, we discussed what &#8220;building software&#8221; is at length within my <a href="https://whynowtech.substack.com/p/nix">Nix primer</a> so I shall point you there if you need a refresher.  </p><p>Zig&#8217;s 4 build modes are:</p><ul><li><p><strong>Debug</strong> = used during development (ie writing your code) and prioritises ease of debugging over performance. In this mode, code is compiled with additional debugging info.</p></li><li><p><strong>ReleaseSafe</strong> = used for the final build of an application when performance and optimisation are critical. </p></li><li><p><strong>ReleaseSmall</strong> = prioritises generating the smallest possible &#8220;executable&#8221;. Achieved through techniques such as dead code (ie unused) elimination or &#8220;function/data merging&#8221; (removing duplicates). This mode&#8217;s particularly useful for embedded systems (e.g., a <a href="https://en-uk.ring.com/">Ring doorbell</a>) that have limited resources (compute/memory).</p></li><li><p><strong>ReleaseFast</strong> = sits in between debug and release modes. Optimises for performance but still includes some additional debugging info.         </p></li></ul><p>You select one of these build modes via the command line like so: </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8x2u!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8x2u!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 424w, https://substackcdn.com/image/fetch/$s_!8x2u!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 848w, https://substackcdn.com/image/fetch/$s_!8x2u!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 1272w, https://substackcdn.com/image/fetch/$s_!8x2u!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8x2u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png" width="1456" height="209" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:209,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:54958,&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_!8x2u!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 424w, https://substackcdn.com/image/fetch/$s_!8x2u!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 848w, https://substackcdn.com/image/fetch/$s_!8x2u!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 1272w, https://substackcdn.com/image/fetch/$s_!8x2u!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2960fbe-7cb9-4926-b87c-02ca4fd1dc78_1718x247.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>In particular, these build modes speak to Zig&#8217;s stated goal of producing <em>optimal</em> and <em>reusable </em>software. Wanna run some Zig code on your toaster? Cool, use ReleaseSmall. Fancy building a database? Impressive, but please use ReleaseSafe.    </p><div><hr></div><p>As hard as it may be to believe, there&#8217;s <em>so much more</em> (build.zig, cross-compilation, etc.) that I&#8217;d like to take you through re. Zig. However, I feel like the law of diminishing returns is almost certainly kicking in already. </p><p>I suspect you &#8220;get it&#8221;, you understand the essence and purpose of Zig. I&#8217;d encourage you to jump into the following posts/videos if you&#8217;re interested in learning more:</p><ul><li><p>Mitchell Hashimoto: <a href="https://mitchellh.com/zig/build-internals">Zig Build Internals</a>.</p></li><li><p>Fastly: <a href="https://www.fastly.com/blog/building-an-efficient-and-portable-programming-language-with-zig">Build an Efficient &amp; Portable Programming Language with Zig</a>.</p></li><li><p>Andrew Kelley: <a href="https://www.youtube.com/watch?v=Gv2I7qTux7g">The Road to Zig 1.0</a>.</p></li></ul><p>As I have espoused many times, I like <a href="https://whynowtech.substack.com/p/webgpu">&#8220;Serious Software&#8221;</a>. Think game engines, 3d modelling software, runtimes, etc., as the &#8220;real estate&#8221; of features that can (and should!) be optimised within them is tremendous. Good luck building <a href="https://www.blender.org/">Blender</a> over a weekend!</p><p>Jarred <a href="https://bun.sh/#:~:text=In%20one%20word%3A%20obsession.%20An%20enormous%20amount%20of%20time%20spent%20profiling%2C%20benchmarking%20and%20optimizing%20things.%20The%20answer%20is%20different%20for%20every%20part%20of%20Bun%2C">puts it</a> similarly when asked &#8220;Why is Bun Fast?&#8221;: <em>&#8220;In one word: obsession. An enormous amount of time spent profiling, benchmarking and optimising things. <strong>The answer is different for every part of Bun</strong>&#8221;</em>.</p><p>I suspect Zig will continue to make it easier for more folk like Jarred to lean into their obsessions and take on incumbents through fine-grained tweaks and tuning. If so, I am very excited to see what&#8217;s coming around the corner.</p><div class="pullquote"><p><strong>If you are building, or considering building, with Zig, I&#8217;d love to say hello! alex@tapestry.vc</strong> </p></div><p><a href="https://github.com/sponsors/ziglang">Finally, I&#8217;d ask that, if possible, you consider supporting the Zig Software Foundation.</a> </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thank you, as always, for reading. Subscribe for my next primer on <a href="https://tigerbeetle.com/">TigerBeetle</a>!</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[*Bonus* Remaking Pokemon Yellow in Godot]]></title><description><![CDATA[Alex used Godot, it was super effective.]]></description><link>https://whynowtech.substack.com/p/bonus-remaking-pokemon-yellow-in</link><guid isPermaLink="false">https://whynowtech.substack.com/p/bonus-remaking-pokemon-yellow-in</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Wed, 12 Apr 2023 15:48:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6F35!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>Welcome to new subs + thanks a million for the <a href="https://whynowtech.substack.com/p/secure-enclaves">Secure Enclaves</a> love! This thing has grown a whole lot faster than my inner pessimist could have imagined. So, grazie!<br></em></p><p><em><strong>If you enjoy these primers, I&#8217;d appreciate it if you favourite this post&#8217;s <a href="https://twitter.com/alex__mackenzie">tweet</a> to help spread the good (?) word of Why Now!</strong></em></p><p><em>As always, I&#8217;m at alex@tapestry.vc should you ever wish to chat.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6F35!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6F35!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png 424w, https://substackcdn.com/image/fetch/$s_!6F35!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png 848w, https://substackcdn.com/image/fetch/$s_!6F35!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png 1272w, https://substackcdn.com/image/fetch/$s_!6F35!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6F35!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png" width="1280" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image&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="image" title="image" srcset="https://substackcdn.com/image/fetch/$s_!6F35!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png 424w, https://substackcdn.com/image/fetch/$s_!6F35!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png 848w, https://substackcdn.com/image/fetch/$s_!6F35!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.png 1272w, https://substackcdn.com/image/fetch/$s_!6F35!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc27d82ed-e6ee-43b2-b7c5-5ff649f46af1_1280x720.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>For awhile now I&#8217;ve been ruminating on what it would take to dethrone Unity. Why? Well, game studio revenue follows a power law similar to the one that venture obeys. So, if you back the right engine you back the right index.</p><p>This is why &#8220;infrastructure&#8221; &#8212; everything from databases to build systems &#8212; is a compelling investment category to me. Infrastructure is an index of.. innovation.. a little (<em>lot</em>) cringe I know, but true? </p><p>Anyway, back to Unity. We&#8217;re witnessing the &#8220;rise of indie&#8221; in gaming. <a href="https://whynowtech.substack.com/p/webgpu">WebGPU</a> is (<a href="https://developer.chrome.com/blog/webgpu-release/">officially!</a>) bringing high-performance/fidelity gaming to the browser, Xbox&#8217;s Game Pass is <em>actually &#8220;</em>Netflix for gaming&#8221; and LLMs mean that what used to take <em>hours</em> (sprite sheets in <a href="https://www.piskelapp.com/">Piskel</a>) takes minutes. </p><p>Not to mention the fact that my mother is <em>crushing it </em>on Candy Crush. </p><p>Godot would appear to be the indie developer&#8217;s engine of choice. So, I decided to pick it up last September to ease the imposter syndrome (I usually build &#8220;traditional&#8221; software). I recreated the very first Game Boy game I ever laid my youthful eyes on. Pokemon Yellow! </p><p>I documented the development process on my blog (<a href="http://mack.work">mack.work</a>) + decided it&#8217;d be fun to share it today as a *bonus* Why Now issue. I will likely write-up a similar post on my process of learning <a href="https://ziglang.org/">Zig</a> soon. <em>Lmk what you think of this format?</em></p><p>PS - this was pre the latest GenAI boom, so I did indeed spend ~2 hours drawing all the game assets pixel-by-pixel. I also had to learn Godot&#8217;s native scripting language (GDScript). Kinda crazy how much has changed since!</p><p>The next Why Now primer is under construction (hint, hint) so stay tuned. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Join Charizard, Blastoise and Venusaur in subscribing to Why Now!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3><strong>Creating the Main Character</strong></h3><p>First, I created a "Player" scene that contains an AnimatedSprite &amp; a CollisionShape2D. I created the player animations in <a href="https://mack.work/piskelapp.com">Piskel</a></p><p><a href="https://www.loom.com/share/7ef3a576c5744129862a77acf13c3183">Pokemon_Yellow_Remastered - Godot Engine - Watch Video</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OLg2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OLg2!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif 424w, https://substackcdn.com/image/fetch/$s_!OLg2!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif 848w, https://substackcdn.com/image/fetch/$s_!OLg2!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!OLg2!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OLg2!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif" width="640" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:640,&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_!OLg2!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif 424w, https://substackcdn.com/image/fetch/$s_!OLg2!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif 848w, https://substackcdn.com/image/fetch/$s_!OLg2!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!OLg2!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd587bb3c-38dc-48d8-b421-9a64b98e7804_640x360.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>I then added code to make the player's animations dynamic &amp; to enable the player to move. The code below is written in "GDScript", Godot's DSL that resembles Python.</p><pre><code><code>extends KinematicBody2D

export var speed = 400
var screen_size

func _ready():
    screen_size = get_viewport_rect().size
        
func _physics_process(delta):
    var velocity = Vector2.ZERO # The player's movement vector.
    if Input.is_action_pressed("move_right"):
        velocity.x += 1
    if Input.is_action_pressed("move_left"):
        velocity.x -= 1
    if Input.is_action_pressed("move_down"):
        velocity.y += 1
    if Input.is_action_pressed("move_up"):
        velocity.y -= 1        

    if velocity.length() &gt; 0:
        velocity = velocity.normalized() * speed
        $AnimatedSprite.play()
    else:
        $AnimatedSprite.stop()
        
    position += velocity * delta

    if velocity.x != 0:
        $AnimatedSprite.animation = "Walking_Sideways"
        $AnimatedSprite.flip_v = false
        $AnimatedSprite.flip_h = velocity.x &lt; 0
    if velocity.y &gt; 0:
        $AnimatedSprite.animation = "Walking_Down"
    elif velocity.y &lt; 0:
        $AnimatedSprite.animation = "Walking_Up"

    move_and_collide(velocity * delta)
  </code></code></pre><h3><strong>Creating Pallet Town</strong></h3><p>I found a Pallet Town sprite sheet &amp; edited it in Figma. I used CollisionPolygon2D to create custom collision shapes in order to allow the player to walk on top of doors.</p><p>In time, when a player steps on these doors they'll "enter" the house.</p><p><a href="https://www.loom.com/share/6ab42f0c40b54b29aeb368d481b20925">Godot - Player Scene - Watch Video</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!s8rH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!s8rH!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!s8rH!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!s8rH!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!s8rH!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!s8rH!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif" width="576" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:576,&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_!s8rH!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!s8rH!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!s8rH!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!s8rH!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb731745a-52c9-43fa-9ba4-b4d15f2c52e1_576x360.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><h3><strong>Creating a Menu</strong></h3><p>I'm currently creating a popup menu that's triggered by pressing the "M" key &amp; closed via pressing the "Esc" key or pressing "Enter" on the "Exit" menu option.</p><p>Note, when the popup menu is opened, the arrow keys typically used to move the Player must now instead, be used to navigate the menu.</p><p>I used Godot's "Focus" UI properties to enable an event-based navigation arrow that corresponds to the appropriate arrow keys.</p><p><a href="https://www.loom.com/share/b469657f1b3e4cdaa896fcca137f3bb2">Godot - Main Menu Scene</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JzY5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JzY5!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!JzY5!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!JzY5!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!JzY5!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JzY5!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif" width="576" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:576,&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_!JzY5!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!JzY5!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!JzY5!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!JzY5!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34272853-9815-4d62-b023-ffcd6fd73792_576x360.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><br>See main menu code below. Go easy on me, I'll refactor later.</p><pre><code><code>extends Node

signal menu_opened
signal menu_closed

func _ready():
    $Menu.hide()
    $Menu/VBoxContainer/Pokedex/Arrow1.hide()
    $Menu/VBoxContainer/Pokemon/Arrow2.hide()
    $Menu/VBoxContainer/Item/Arrow3.hide()
    $Menu/VBoxContainer/Ash/Arrow4.hide()
    $Menu/VBoxContainer/Save/Arrow5.hide()
    $Menu/VBoxContainer/Option/Arrow6.hide()
    $Menu/VBoxContainer/Exit/Arrow7.hide()
    
    
func _process(delta):
    if Input.is_action_pressed("Menu_Open"):
        $Menu.show()
        $Menu/VBoxContainer/Pokedex.grab_focus()
        emit_signal("menu_opened")
    
    if Input.is_action_pressed("Menu_Close"):
        $Menu.hide()
        emit_signal("menu_closed")
    
# Arrow navigation.        
    
func _on_Pokedex_focus_entered():
    $Menu/VBoxContainer/Pokedex/Arrow1.show()

func _on_Pokedex_focus_exited():
    $Menu/VBoxContainer/Pokedex/Arrow1.hide()    

func _on_Pokemon_focus_entered():
    $Menu/VBoxContainer/Pokemon/Arrow2.show()

func _on_Pokemon_focus_exited():
    $Menu/VBoxContainer/Pokemon/Arrow2.hide()

func _on_Item_focus_entered():
    $Menu/VBoxContainer/Item/Arrow3.show()

func _on_Item_focus_exited():
    $Menu/VBoxContainer/Item/Arrow3.hide()

func _on_Ash_focus_entered():
    $Menu/VBoxContainer/Ash/Arrow4.show()

func _on_Ash_focus_exited():
    $Menu/VBoxContainer/Ash/Arrow4.hide()

func _on_Save_focus_entered():
    $Menu/VBoxContainer/Save/Arrow5.show()

func _on_Save_focus_exited():
    $Menu/VBoxContainer/Save/Arrow5.hide()

func _on_Option_focus_entered():
    $Menu/VBoxContainer/Option/Arrow6.show()

func _on_Option_focus_exited():
    $Menu/VBoxContainer/Option/Arrow6.hide()

func _on_Exit_focus_entered():
    $Menu/VBoxContainer/Exit/Arrow7.show()

func _on_Exit_focus_exited():
    $Menu/VBoxContainer/Exit/Arrow7.hide()
</code></code></pre><p>Next, I created a sub menu for each item. This was pretty straightforward given I already built the UI focus logic. I plan on returning to the "Save" sub menu later once I grok working with databases/storage via Godot.</p><pre><code><code>if $Menu.visible == true:
        if $Menu/VBoxContainer/Exit.has_focus():
            if Input.is_action_pressed("ui_select"):
                emit_signal("menu_closed")
                $Menu.hide()
        
        if $Menu/VBoxContainer/Pokedex.has_focus():
            if Input.is_action_pressed("ui_select"):
                $Menu/Haunter.show()
            if Input.is_action_pressed("ui_back"):
                $Menu/Haunter.hide()
</code></code></pre><p>I had a bunch of fun building Professor Oak's Lab &amp; the "scene switching" logic. Essentially what happens here is that when my animated spite enters the collision path of Oak's Lab's door, a signal fires which causes the "Oak's Lab" scene to be loaded.</p><p><a href="https://www.loom.com/share/2472d31034ff42a49c39cdc81c597396">Loom Message - 9 October 2022 - Watch Video</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c4lg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c4lg!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!c4lg!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!c4lg!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!c4lg!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c4lg!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif" width="576" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:576,&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_!c4lg!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!c4lg!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!c4lg!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!c4lg!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3526aac1-3aa2-4368-9209-2cc7f85b8b05_576x360.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>Pallet Town script.</p><pre><code><code>extends Control

func _on_Area2D_body_entered(body):
    get_tree().change_scene("res://OaksLab.tscn")</code></code></pre><p>Oak's Lab script.</p><pre><code><code>extends Node2D

signal exited_oaks_lab_interior

func _on_Area2D_body_entered(body):
    emit_signal("location_changed")
    get_tree().change_scene("res://Main.tscn")</code></code></pre><p>Admittedly what I have not figured out yet (tips welcome!) is how to change the starting position of my animated sprite when exiting Oak's Lab so that the sprite appears as though he's just exited the door of the lab. Something to do with changing the position variable's value based on signals I suspect.</p><p>Added a camera to the game which was pretty simple but has added a real sense of presence to the world.</p><p><a href="https://www.loom.com/share/873b7041192441e893512ba95af3021c">Loom Message - 9 October 2022 - Watch Video</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eiMq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eiMq!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!eiMq!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!eiMq!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!eiMq!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eiMq!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif" width="576" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:360,&quot;width&quot;:576,&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_!eiMq!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif 424w, https://substackcdn.com/image/fetch/$s_!eiMq!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif 848w, https://substackcdn.com/image/fetch/$s_!eiMq!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.gif 1272w, https://substackcdn.com/image/fetch/$s_!eiMq!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbad8af7-c134-43aa-8089-767b963ca3f5_576x360.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>]]></content:encoded></item><item><title><![CDATA[Secure Enclaves]]></title><description><![CDATA[Dance like no one is watching, encrypt like everyone is]]></description><link>https://whynowtech.substack.com/p/secure-enclaves</link><guid isPermaLink="false">https://whynowtech.substack.com/p/secure-enclaves</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Mon, 03 Apr 2023 15:18:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!pugk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>Welcome to new subs + thanks a million for the <a href="https://whynowtech.substack.com/p/webgpu">WebGPU</a> love! This thing has grown a whole lot faster than my inner pessimist could have imagined. So, grazie!<br></em></p><p><strong>If you enjoy these primers, I&#8217;d appreciate it if you favourite this post&#8217;s <a href="https://twitter.com/alex__mackenzie">tweet</a> to help spread the good (?) word of Why Now!</strong></p><p><em><br>As always, I&#8217;m at alex@tapestry.vc should you ever wish to chat.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pugk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pugk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png 424w, https://substackcdn.com/image/fetch/$s_!pugk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png 848w, https://substackcdn.com/image/fetch/$s_!pugk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png 1272w, https://substackcdn.com/image/fetch/$s_!pugk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pugk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png" width="1456" height="859" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:859,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:550764,&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_!pugk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png 424w, https://substackcdn.com/image/fetch/$s_!pugk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png 848w, https://substackcdn.com/image/fetch/$s_!pugk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.png 1272w, https://substackcdn.com/image/fetch/$s_!pugk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7717d0c-6e56-487e-846b-aa1adc8fe70f_1462x863.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">Yes &#8212; I did brand this primer like the next cool devtool.</figcaption></figure></div><p>Many smart friends are 50/50 on cybersecurity as a pre-seed/seed investment category. I have always been perplexed by this. </p><p>From my vantage-point, security is one of the few categories where actors are just as incentivised to &#8220;innovate&#8221; on problem vs. solution creation. Thus, upstarts are provided with wedges to take on incumbents. </p><p>The second criminally under-discussed topic in the world of technology investing is cybersecurity&#8217;s role in the &#8220;Why Now&#8221; market equation. </p><p>Without asymmetric encryption (the &#8220;s&#8221; in https) the modern internet as we know it wouldn&#8217;t have thrived. Talk about a firm <a href="https://www.cloudflare.com/en-gb/learning/ssl/what-happens-in-a-tls-handshake/">grip</a> (..sorry) on innovation! There&#8217;s more:</p><ul><li><p>Pioneering remote-first companies (a la GitLab) without VPNs (+ perhaps SSH) would likely have struggled to operate. Would Deel be a company?</p></li><li><p>The emerging &#8220;isolate cloud&#8221; (Deno, <a href="https://grafbase.com/">Grafbase</a>, etc) is partially a second-order outcome of Chrome&#8217;s need to sandbox untrusted code.</p></li><li><p>Microservices wouldn&#8217;t have proliferated to the same degree without service meshes a la Envoy. (&amp; more recently, eBPF). </p></li><li><p>And, as I&#8217;ve written <a href="https://whynowtech.substack.com/p/federated-learning">[1]</a><a href="https://whynowtech.substack.com/p/webgpu">[2]</a> about previously, broad-scale personalised ML models will not be &#8220;a thing&#8221; (technical term) without privacy-enhancing technologies (PETs).</p></li></ul><p>Ok, point proven. So what&#8217;s next in cybersecurity?</p><p>Famous last words, but the &#8220;final frontier&#8221; has always been to encrypt data across its three states: <em>at-rest</em>, <em>in-transit</em> &amp; <em>in-use</em>. </p><p>Why? Because if sensitive data like your <code>FullName</code> is perennially encrypted (e.g., &#8220;<strong>De2CYsx&#8221;) </strong>it&#8217;s rather difficult for a malicious actor to do anything untowardly.</p><p>Conveniently, how we secure data in-use has three &#8220;states&#8221; also: fully homomorphic encryption (FHE), trusted platform modules (TPM), and <em><strong>secure enclaves</strong></em>. </p><p>As you may have ..deciphered.. from the title of this primer, we&#8217;ll be delving into secure enclaves &#8212; the approach many hardware (Intel/AMD) + software/cloud (AWS/Azure) giants are hanging their hats on.</p><p>Within this primer we&#8217;ll discuss:   </p><ul><li><p>A ~brief history of encryption. </p></li><li><p>Approaches to data in-use security. </p></li><li><p>Secure Enclaves. You&#8217;d hope! </p></li></ul><p>Thanks to friends <a href="https://twitter.com/NevFlynn">Nev</a>, <a href="https://twitter.com/LiamPTFarrelly">Liam</a> &amp; <a href="https://twitter.com/Ecmoy">Liz</a> at <a href="https://evervault.com/">Evervault</a> for the inspiration for this post + for reviewing!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">print(decrypt(CYdEsx--))                                            &#8220;Subscribe&#8220;</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>Yes, the above caption was my attempt of humour! .. just subscribe?</p><div><hr></div><p>Secure Enclaves are <strong>highly-constrained</strong> compute environments that allow for <strong>cryptographic </strong>verification (<strong>attestation</strong>) of the code being executed. </p><p>As always, let&#8217;s cherry-pick the complexity out of this definition &amp; take it step-by-step. First, some history. </p><div><hr></div><p><strong>Encryption &#8212; A Brief History (2023), Alexander Mackenzie</strong></p><p><em>Cryptography</em><strong> </strong>is the practice &amp; study of techniques of secure communication in the presence of adversarial behaviour. </p><p><em>Encryption</em> is the process (&amp; in many ways, art) of scrambling data so that only authorised parties can understand the underlying information. So yes, encryption is a subset of cryptography. </p><p>In and around 100BC Julius Caesar was slinging secret messages around Caput Mundi (aka Rome) via a relatively simple substitution &#8220;cipher&#8221; (ie encrypt/decrypt function) now known as the &#8220;Caesar Cipher&#8221;.</p><p>This was a relatively simple &#8220;shift-by-three&#8221; cipher. Meaning that the letter &#8220;A&#8221; would be substituted with the letter &#8220;D&#8221;, the letter &#8220;X&#8221; would be substituted with &#8220;A&#8221;, etc.  </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A4cE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A4cE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png 424w, https://substackcdn.com/image/fetch/$s_!A4cE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png 848w, https://substackcdn.com/image/fetch/$s_!A4cE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png 1272w, https://substackcdn.com/image/fetch/$s_!A4cE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A4cE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png" width="1456" height="1018" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1018,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:666592,&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_!A4cE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png 424w, https://substackcdn.com/image/fetch/$s_!A4cE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png 848w, https://substackcdn.com/image/fetch/$s_!A4cE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.png 1272w, https://substackcdn.com/image/fetch/$s_!A4cE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4708a0fa-bbd1-4336-a62e-7ed9495c5a59_1462x1022.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">Caesar Shift-By-Three Cipher</figcaption></figure></div><p>What&#8217;s pertinent here is that Caesar Cipher is rule-based encryption. Once someone knows the rules of the game they can easily decrypt the &#8220;ciphertext&#8221; (encrypted text) into &#8220;plaintext&#8221; (decrypted text). </p><p>Astute readers will note that if letters such as &#8220;D&#8221; or &#8220;L&#8221; appear frequently in Caesar&#8217;s ciphertext, that these letters likely map to plaintext vowels (A and I respectively).</p><p>Similarly, readers may look for common bigrams (sequences of letters) in words such as: NG, ST, QU, etc. This strategy is known as &#8220;frequency analysis&#8221;. Not <em>exactly</em> an unbreakable code.</p><p><em>** Modern encryption wasn&#8217;t built in a day either! &#8230; </em>**</p><p>Modern encryption tends to rely on what&#8217;s known as an &#8220;encryption key&#8221; (or <em>key*<strong>s*</strong></em>) which stems from the work of ~<a href="https://en.wikipedia.org/wiki/Blaise_de_Vigen%C3%A8re">Blaise de Vigen&#232;re</a> in the 16th century. <br><br>Encryption keys are a hard-to-guess string of letters, numbers and symbols such as: <code>b'VQfCNh**72dvh</code> that, when combined with a secret message, produce a unique output.</p><p>Below I used the python cryptography library to: </p><ul><li><p>Generate an encryption key</p></li><li><p>Encrypt a message (&#8220;SuBsCrIbE&#8221;.. subtle) with this key </p></li><li><p>Print the ciphertext</p></li><li><p>Decrypt the ciphertext with the key &amp; print the resulting plaintext </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_!7dOD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7dOD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png 424w, https://substackcdn.com/image/fetch/$s_!7dOD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png 848w, https://substackcdn.com/image/fetch/$s_!7dOD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png 1272w, https://substackcdn.com/image/fetch/$s_!7dOD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7dOD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png" width="1456" height="921" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:921,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:563028,&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_!7dOD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png 424w, https://substackcdn.com/image/fetch/$s_!7dOD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png 848w, https://substackcdn.com/image/fetch/$s_!7dOD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.png 1272w, https://substackcdn.com/image/fetch/$s_!7dOD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d545bbc-f1dd-4a67-a625-b30e66ef829b_1840x1164.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">Shoutout to the Raycast team for ray.so!</figcaption></figure></div><p></p><blockquote><p><strong>Technical Detail: </strong>When a single encryption key is used to both encrypt &amp; decrypt data this is known as &#8220;symmetric encryption&#8221;. </p><p>When alternate keys are used to encrypt (public key) and decrypt (private key) data this is known as &#8220;asymmetric encryption&#8221;.</p></blockquote><p><br>Vigen&#232;re used <em>symmetric encryption</em> to make his cipher &#8220;polyalphabetic&#8221; &#8212; whereby each plaintext character (e.g., &#8220;C&#8221;) was combined with an encryption key character (e.g., &#8220;H&#8221;) in order to &#8220;generate&#8221; a character (&#8220;J&#8221;) from a <em>specific</em> alphabet. </p><p>Example below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LzAW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LzAW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png 424w, https://substackcdn.com/image/fetch/$s_!LzAW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png 848w, https://substackcdn.com/image/fetch/$s_!LzAW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png 1272w, https://substackcdn.com/image/fetch/$s_!LzAW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LzAW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png" width="1456" height="1589" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1589,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1234750,&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_!LzAW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png 424w, https://substackcdn.com/image/fetch/$s_!LzAW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png 848w, https://substackcdn.com/image/fetch/$s_!LzAW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.png 1272w, https://substackcdn.com/image/fetch/$s_!LzAW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa320e97c-ba6b-4db1-9120-32ff091f114a_1770x1932.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>However, this method and its 19th/20th century successors (including the German <a href="https://en.wikipedia.org/wiki/Enigma_machine">Enigma</a> rotor machine!) once again eventually fell short when frequency analysis was used. </p><p><em>** I&#8217;m oversimplifying what it took to crack Enigma to the nth degree here! **</em></p><p>Fast-forward to the 1970s and IBM designed a cipher (remember, an encrypt/decrypt function) named Lucifer. A bit.. disconcerting? </p><p>Yet, despite this, the cipher was later adopted by NIST (National Institute of Standards &amp; Technology) as a US national standard and (thankfully) renamed to the Data Encryption Standard, or &#8220;DES&#8221;.</p><p>Elsewhere in the 1970s (1976) our friend <em>asymmetric encryption </em>(remember, public <em>and </em>private keys) began to bloom thanks to Whitfield Diffie &amp; Martin Hellman. The advent of asymmetric encryption marked the dawn of &#8220;modern&#8221; cryptography. <br></p><blockquote><p><strong>Key Point:</strong> Thanks to asymmetric encryption, parties no longer need a shared secret (encryption key) to securely communicate. <br><br>Alice can share her public key with Bob in order to encrypt a &#8220;secret message&#8221; from Bob, but she never has to share her private (decryption) key with him. <br><br>Take a second to internalise this as it&#8217;s important!</p></blockquote><p><br>Shortly after (1977), fuelled by <a href="https://en.wikipedia.org/wiki/Manischewitz">Manischewitz</a> (worth looking into), <strong>R</strong>ivest, <strong>S</strong>hamir and <strong>A</strong>dleman released the RSA asymmetric cipher. Yes&#8230; like the conference. RSA is the most popular / widely understood asymmetric encryption system to date. </p><p>However, as I alluded to in this primer&#8217;s opening paragraph: the incentive to create new problems in cybersecurity is high. Come 1997, DES was cracked. <em>Symmetric</em> encryption needed a new saviour. </p><p>How was it cracked? Well, thanks to <em>Ye Olde</em> &#8220;Moore&#8217;s Law&#8221;<em> </em>clock speeds (see WebGPU <a href="https://whynowtech.substack.com/p/webgpu#:~:text=CPU%20performance%20is%20often%20measured%20by%20%E2%80%9Cclock%20speed%E2%80%9D.%20Clock%20speed%20%3D%3D%20the%20number%20of%20compute%20cycles%20a%20CPU%20handles%20per%20second.%20Let%E2%80%99s%20not%20get%20into%20%E2%80%9Ccompute%20cycles%E2%80%9D%20in%20this%20post%20%E2%80%94%20just%20know%20that%2C%20all%20else%20being%20equal%2C%20the%20more%20compute%20cycles%20a%20CPU%20can%20handle%20per%20second%2C%20the%20more%20%E2%80%9Cperformant%E2%80%9D%20a%20computer%20is.">primer</a>) improved. </p><p>This meant that via sheer brute-force computation (ie trying every possible solution), malicious actors could correctly guess a 56-bit DES encryption key, and hence, access an underlying message. </p><p>Thus, in 1997, another RFP was published by NIST for a new national standard. By the second millennium (yes, 2000), a new cipher was adopted known as Rijndael (pronounced rain-dahl) or the <em>Advanced</em> Encryption Standard.  </p><p>Without getting into the mathematical weeds, one of AES&#8217; main advantages is that it offers 128-bit, 192-bit or 256-bit encryption keys. </p><p>For context, even with a supercomputer, it would take <strong>1 billion billion years</strong> to crack a 128-bit AES key using brute force attack.</p><p><em>** Cue the &#8220;but what about post-quantum cryptography!&#8221; outcry **</em></p><p>A fair Q &#8212; quantum is/was a <em>very real</em> threat. </p><p>In 2016, NIST&#8230; you guessed it, put out another RFP for cryptographers to devise and then vet encryption methods that could resist an attack from future quantum computers. </p><p>In July &#8216;22 the first four quantum-resistant algorithms (thank you <a href="https://en.wikipedia.org/wiki/Lattice-based_cryptography#:~:text=Lattice%2Dbased%20cryptography%20is,cannot%20be%20solved%20efficiently">lattices</a>) were announced (!) which I&#8217;m, naturally, paying quite a bit of attention to, but are well-beyond the scope of this primer. </p><p><em>** Encryption - fin **</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">..Subscribe for more circuitous historic preambles pre the actual topic of the primer..</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Secure Enclaves are <strong>highly-constrained</strong> compute environments that allow for <strong><s>cryptographic</s> </strong>verification (<strong>attestation</strong>) of the code being executed. </p><p>Ok &#8212; so what does &#8220;data in-use&#8221; mean. Why is it a particularly difficult problem to solve? </p><p>As mentioned, data has three states: </p><ul><li><p>It&#8217;s &#8220;at-rest&#8221; (&#128546;) when it&#8217;s idle (e.g., stored in a database).</p></li><li><p>It&#8217;s &#8220;in-transit&#8221; when sent across a network (e.g., from your phone to the cloud).</p></li><li><p>It&#8217;s &#8220;in-use&#8221; when it&#8217;s being used/processed in some way (e.g., rendering a UI). </p></li></ul><p>The challenge is, when we want to <em>use</em> data we ~can&#8217;t keep it encrypted. Why? well, it&#8217;s tricky to do some math on a value such as: &#8220;<em>De2CYsx&#8221;. </em>So, at some point we need to decrypt data if we want to process it. <em> </em></p><p>However, it&#8217;s when we end up decrypting <em>ciphertext</em> into <em>plaintext </em>that things get.. precarious. Hence, data in-use security = holy grail (sorry TLS). <em> </em></p><p>Ok, so what have we done about this problem-space to date? </p><div><hr></div><p>An alternative to secure enclaves is <strong>homomorphic encryption (</strong>HE<strong>)</strong>. An encryption &#8220;scheme&#8221; (ie approach) proposed as early as 1978, what a time to be <em>A[iV3</em> for cryptographers! </p><p>HE enables someone to process data (derive a value from it) without ever having to decrypt the data. Think about what this means for a second:</p><p>With HE, we can pass some ciphertext (yes, De2CYsx) as an argument of a function that calculates the sum of 2 + De2CYsx and returns the same answer that it would if De2CYsx was decrypted (perhaps a number like 3?). See below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kQxk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kQxk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png 424w, https://substackcdn.com/image/fetch/$s_!kQxk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png 848w, https://substackcdn.com/image/fetch/$s_!kQxk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png 1272w, https://substackcdn.com/image/fetch/$s_!kQxk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kQxk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png" width="1048" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1048,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:250727,&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_!kQxk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png 424w, https://substackcdn.com/image/fetch/$s_!kQxk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png 848w, https://substackcdn.com/image/fetch/$s_!kQxk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.png 1272w, https://substackcdn.com/image/fetch/$s_!kQxk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b8f7e7e-7170-4e7f-83fe-4386fd2a3286_1048x720.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>Pretty cool, huh? However, as perhaps expected in the field of cryptography, nothing is quite as it seems.</p><p>Firstly, homomorphic encryption schemes can be <em>partial</em> <em>or</em> <em>&#8220;somewhat&#8221; </em>vs.<em> full</em>.</p><p>Partial (PHE) or Somewhat (SHE) means that only certain mathematical operations (multiplication and/or addition) can be conducted on the ciphertext. </p><p>This is fine, but we&#8217;re not quite at the promised land here. Computers tend to do a little more than multiplication/addition.</p><p>However, come 30 years later and we kinda are. Craig Gentry (&amp; co) came along in 2009 with a <em>fully homomorphic encryption </em>(you guessed it, FHE) scheme. FHE, in theory at least, enables <em>anyone</em> to perform <em>any operation</em> on ciphertext.<br></p><blockquote><p><strong>Note: </strong>Within these primers I typically <em>try</em> to leave no stone unturned when explaining how something works. </p><p>For homomorphic encryption I think this would be a mistake. Each homomorphic encryption scheme is nuanced &amp; requires some pretty hardcore math. </p><p>If you&#8217;re really into your prime numbers (<a href="https://tenor.com/O2X5.gif">&#8230;</a>), check out the <a href="https://en.wikipedia.org/wiki/Paillier_cryptosystem">Paillier cryptosystem</a> which is an approach I quite enjoyed digging into.   </p></blockquote><p><br>At this point you&#8217;re likely thinking &#8212; &#8220;why isn&#8217;t this primer about FHE then?&#8221;. Fair.  </p><p>Well, the issue with FHE is that it requires a meaningful amount of compute and/or time to calculate a new value from ciphertext inputs. </p><p>To put this into context, IBM released its improved (!) HElib C++ library for FHE in 2018. A calculation that would take a second to perform using plaintext would take an average of <strong>11.5 days (!)</strong> to perform using the 2018 version of HElib. </p><p>As a wise individual once <em>loosely</em> said &#8212; <em>no person has any time time for that.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">However, perhaps they <em>do </em>have time to subscribe?.. maybe</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Time for this primer&#8217;s raison d'&#234;tre &#8212; <em>secure enclaves.</em></p><p>Ok, so an alternative to processing ciphertext is&#8230; to process plaintext. Shocker.</p><p>However, we know that exposing plaintext is the root of all data security problems. So, what can we do?</p><p>Well, we need to first work backwards to understand <em>how</em> this plaintext data may be accessed and by <em>whom</em>. Once we know the threat, we can form a response. </p><p>Let&#8217;s use AWS EC2 as an example. In its least-flattering light, EC2 is rented &#8220;compute&#8221; (ie CPU processing). </p><p>A given AWS EC2 &#8220;instance&#8221; is broadly composed of the following components: users (employees/contractors), 3rd party libraries, applications and an operating system. These components are the <em>whom </em>and should not be trusted.</p><p>Moving swiftly onto the how. In computing, when we want to process some data or code, our operating system loads this data from &#8220;storage&#8221; (e.g., a hard drive) to &#8220;memory&#8221; (ie RAM). The same is hence true for EC2.<br><br>In storage our data is &#8220;at-rest&#8221;, and hence, encrypted. However, when loaded into RAM it&#8217;s decrypted so that it can be used. <em>Et voila! Un gros probl&#232;me. </em></p><p>This is the <em>how. </em>Many methods, such as &#8220;<a href="https://www.google.com/search?q=memory+scraping&amp;oq=memory+scraping&amp;aqs=chrome..69i57j0i512j0i15i22i30l3j0i10i15i22i30j0i390i650l2.391j0j7&amp;sourceid=chrome&amp;ie=UTF-8#:~:text=Memory%2Dscraping%20malware,wiki%20%E2%80%BA%20Memory%2Dscraping_m...">memory scraping</a>&#8221;, exist that exploit plaintext that&#8217;s exposed in memory. Cybersecurity is hard.  </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QmN4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QmN4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png 424w, https://substackcdn.com/image/fetch/$s_!QmN4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png 848w, https://substackcdn.com/image/fetch/$s_!QmN4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png 1272w, https://substackcdn.com/image/fetch/$s_!QmN4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QmN4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png" width="1456" height="550" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/faaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:550,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:149128,&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_!QmN4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png 424w, https://substackcdn.com/image/fetch/$s_!QmN4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png 848w, https://substackcdn.com/image/fetch/$s_!QmN4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.png 1272w, https://substackcdn.com/image/fetch/$s_!QmN4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffaaf5035-e78f-48f8-8526-40c413ab8579_1937x732.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">Encrypted data at-rest being converted to decrypted data in-use</figcaption></figure></div><p>So, what can be done to make the processing of this plaintext more secure? </p><p>Well, there is a handful of approaches that various secure enclave providers take. We&#8217;ll keep the example alive + analyse AWS&#8217; Nitro Enclaves offering which is leveraged by the likes of <a href="https://evervault.com/">Evervault</a>, <a href="http://crypto.com">Crypto.com</a>, <a href="https://www.anjuna.io/">Anjuna</a>, etc.</p><p>Nitro Enclaves creates an isolated environment that&#8217;s a <em>peer </em>(just think <em>linked in some way</em>)<em> </em>to another EC2 instance (the &#8220;parent&#8221;) that you&#8217;re running. We load and process our sensitive data in this enclave. </p><p>As alluded to, this peer is a little different, more.. constrained.</p><p>For example, your Nitro Enclave has no internet access, no shell (e.g., SSH) access, no persistent storage and it runs its own kernel. Good luck to anyone trying to exfiltrate sensitive data from an enclave that isn&#8217;t connected to the internet.<br></p><blockquote><p><strong>Technical Detail: </strong>SSH = &#8220;secure shell&#8221;. A shell is a command-line interface (or CLI) that acts as an intermediary between a user and an operating system.<br><br>When you open up your mac &#8220;terminal&#8221; you ultimately use a shell program (e.g, &#8220;<em>zsh&#8221; </em>or &#8220;<em>bash&#8221;</em>)<em> </em>to interact with the OS. <br><br>SSH is a.. secure.. way to remotely access (or &#8220;tunnel&#8221; into) a given machine, remotely. We don&#8217;t want folk to do this when sensitive data&#8217;s involved.  </p></blockquote><p><br>The only way you can bi-directionally communicate with this secure enclave is via a &#8220;Unix Socket&#8221; (don&#8217;t worry about this) that connects to the enclave&#8217;s &#8220;parent&#8221; EC2 instance. </p><p>Why stop here though? &#8220;Defence in depth&#8221;, or, the more technical term: being a pain in the @$$ multiple times, is a strategy worth adhering to.       </p><p>When &#8220;instantiating&#8221; (ie creating) a Nitro Enclave, a user specifies a number of parameters such as: </p><ul><li><p>What application code the enclave will run.</p></li><li><p>The enclave&#8217;s software dependencies. </p></li><li><p>How much memory it will require. </p></li><li><p>How many CPU cores it will need. </p></li></ul><p>These inputs are fed into a hash function that produces a ~unique &#8220;checksum&#8221; (ie hash, ie string of characters) based on its inputs. You may remember checksums from the Why Now post on <a href="https://whynowtech.substack.com/p/nix">Nix</a>.  </p><p>This <em>cryptographic attestation</em> is a bit of a game changer. Now, each time we want to use our enclave to process some sensitive data, we can first <em>check </em>whether or not the secure enclave&#8217;s inputs still produce the same hash. </p><p>If so, we know we&#8217;re running the same application code, with the same dependencies, in the same way. This allows us to cryptographically prove that our enclaves haven&#8217;t been tampered with in some way. Pretty cool!</p><p>As a wise Disney pop-sensation once said, with secure enclaves we have the best of both worlds: a way to provably protect data in-use, ~performantly. </p><p>Secure Enclaves are <strong><s>highly-constrained</s></strong> compute environments that allow for <strong><s>cryptographic</s> </strong>verification (<strong><s>attestation</s></strong>) of the code being executed. </p><p><em>** Secure Enclaves &#8212; fin **</em></p><div class="pullquote"><p><em>Once again, I&#8217;d appreciate love +/ lambasting on this <a href="https://twitter.com/alex__mackenzie">post&#8217;s tweet</a> to help get Why Now out into the ether further!</em></p><p><em>I&#8217;m at alex@tapestry.vc if you feel like saying hello / trading notes!</em></p></div>]]></content:encoded></item><item><title><![CDATA[WebGPU]]></title><description><![CDATA[Bringing back "Serious Software"]]></description><link>https://whynowtech.substack.com/p/webgpu</link><guid isPermaLink="false">https://whynowtech.substack.com/p/webgpu</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Mon, 06 Feb 2023 17:04:11 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6c4063ea-17c1-42bd-9fdd-ca49a19e1ae6_1456x844.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>Welcome to new subs + thanks a million for the <a href="https://whynowtech.substack.com/p/nix">Nix</a> love! </em></p><p>I am doing my best to resist the innate Irish urge to self-disparage, &amp; instead, ask you all to please favourite (or denigrate!) <em>this <a href="https://twitter.com/alex__mackenzie">post&#8217;s tweet</a>.</em></p><p><em> Either approach helps get Why Now out into the ether further. Thanks!<br><br>As always, I&#8217;m at alex@tapestry.vc should you ever wish to chat.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c4zc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c4zc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png 424w, https://substackcdn.com/image/fetch/$s_!c4zc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png 848w, https://substackcdn.com/image/fetch/$s_!c4zc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png 1272w, https://substackcdn.com/image/fetch/$s_!c4zc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c4zc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png" width="1456" height="844" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:844,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:93104,&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_!c4zc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png 424w, https://substackcdn.com/image/fetch/$s_!c4zc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png 848w, https://substackcdn.com/image/fetch/$s_!c4zc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.png 1272w, https://substackcdn.com/image/fetch/$s_!c4zc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3c14f6-5f06-42ff-a72d-164fb04f1227_2642x1532.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>I absolutely love it (need to get out more in &#8216;23) when technologies have uses far-beyond their intended purpose. Niche, I know. </p><p>Lest we forget that the &#8220;<a href="https://en.wikipedia.org/wiki/Slinky">Slinky</a>&#8221; was a stabilisation spring, Berkeley Packet Filters were for ..filtering.. network packets, and GPUs were solely for rendering computer graphics. Matrix multiplication.. who dis? </p><p>This lineage, twinned with the acronym soup (a la GPGPU, WGL, WGSL, SPIR) that, per <a href="https://mack.work/mackenzies_law.html">Mackenzie&#8217;s Law</a>&#8482;, must accompany anything to do with computer graphics, has tee&#8217;d this primer up rather nicely.  </p><p>Alas, things are going to get worse before they get better.</p><p><em>** Enter &#8220;WebGPU&#8221; **</em></p><p>Web browsers are increasingly converging towards &#8220;operating systems&#8221;; applications (e.g., game engines) that were once primarily used natively are now adequately running within our browsers. How?</p><p>There&#8217;s, of course, no <a href="https://www.canva.com/colors/color-meanings/silver/">#C0C0C0</a> bullet. </p><p>However &#8212; Conflict-Free Replicated Data Types, Operational Transformation, &amp; everyone&#8217;s favourite compilation target, WebAssembly certainly aren&#8217;t impediments. </p><p>Well, we may now soon have another technological arrow in our quiver &#8212; WebGPU.   </p><p>Without revealing too much, let&#8217;s just say that up until this point via &#8220;WebGL&#8221; (we will discuss) the <em>modern</em> GPU has been a second citizen within the browser. WebGPU is changing that.  </p><p>Within this primer we&#8217;ll discuss: </p><ul><li><p>The history of GPUs. </p></li><li><p>The &#8220;graphics pipeline&#8221;.</p></li><li><p>The history of graphics APIs.</p></li><li><p>WebGPU. You&#8217;d hope!</p></li><li><p>What trends +/ applications WebGPU may unlock +/ promulgate.</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">WYPS == will you please subscribe?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Web<strong>GPU</strong> is the <em>working name </em>(work harder, please?) for a <strong>Web API</strong> for <strong>accelerated</strong> <strong>graphics</strong> <em>and </em><strong>compute</strong>.</p><p>As always, let&#8217;s first cherry-pick the complexity out of this definition &amp; take it step-by-step.</p><div><hr></div><p><strong>Act 1, Scene 1 &#8212; the Graphics Processing Unit.</strong> </p><p><em>** If you&#8217;re intimately familiar (<a href="https://whynowtech.substack.com/p/nix#:~:text=If%20you%E2%80%99re%20intimately%20(weird!)%20familiar%20with">weird!</a>) with CPU/GPUs you can skip this section ** </em></p><p>To appreciate the GPU, we must first understand the CPU.</p><p>Central Processing Units are &#8220;chips&#8221; (ie billions of transistors et al packaged) used for &#8220;general purpose&#8221; computation; meaning that these chips are &#8220;architected&#8221; to handle a broad range of, ultimately mathematical (thank you <a href="https://en.wikipedia.org/wiki/George_Boole">George Boole</a>), operations. </p><p>You know when your Salesforce app totals the (de minimis &#128546;) number of leads in your pipeline? Cool, that mathematical operation is handled by your CPU&#8217;s &#8220;Arithmetic-Logic Unit&#8221;. As is the <strong>bold</strong> toggle when you&#8217;re writing a Substack post. <br></p><blockquote><p><strong>Key Point:</strong> CPUs handle (or, &#8220;process&#8221;) the <em>general</em>, often very different, data and actions that your computer takes to run itself and third-party software. </p></blockquote><p><br>It&#8217;s important to note that CPUs are designed to process these disparate operations as quickly as possible &#8212; also known as being optimised for &#8220;low latency&#8221;.</p><p>The &#8220;why&#8221; re. low latency should be clear here &#8212; we are modern, entitled computer users that expect almost prescient (thanks <a href="https://engineering.surveysparrow.com/the-magic-of-optimistic-ui-updates-311351df28b">React</a>) execution (!). However, this demand for low latency is also inextricably linked with <em>how</em> CPUs process instructions. </p><p>Each CPU&#8217;s (or CPU cores&#8217;!) operations are executed serially (ie one at a time). At an <em>almost offensively </em>high-level (ignoring <a href="https://www.linkedin.com/pulse/how-interrupts-handled-processor-detailed-view-vasuki-shankar/?trk=public_profile_article_view">interrupts</a>, etc), revisiting our example, this means that a CPU would execute our Salesforce pipeline arithmetic first, and then once complete, it would execute our <strong>bold</strong> operation in Substack.<br></p><blockquote><p><strong>Technical Detail x2: </strong></p><p><strong>&#8220;Cores&#8221; </strong>are<strong> </strong>essentially mini-CPUs, CPUs within a CPU. They enable(d) some degree of parallel (vs. serial) execution. You may remember how big of a deal the first Intel &#8220;<strong>Dual-Core</strong>&#8221; processor was when launched in 2006?</p><p>CPU performance is often measured by <strong>&#8220;clock speed&#8221;</strong>. Clock speed == the number of compute cycles a CPU handles per second. Let&#8217;s not get into &#8220;compute cycles&#8221; in this post &#8212; just know that, all else being equal, the more compute cycles a CPU can handle per second, the more &#8220;performant&#8221; a computer is.  </p></blockquote><p></p><p>GPUs on the other hand are a little more picky, less.. general purpose. </p><p>How so? Broadly speaking, GPUs have a much more narrowly-scoped &#8220;instruction set architecture&#8221; (or &#8220;ISA&#8221;).</p><p>Without getting into the weeds of ISAs, they basically determine the range of operations a chip can take on the data it receives. I elaborated further on them within the first (&#129401;) Why Now <a href="https://whynowtech.substack.com/p/ebpf#:~:text=Native%20Code%3A%20Machine%20code.%20More%20technically%20known%20as%20a%20CPU%E2%80%99s%20Instruction%20Set%20Architecture%20(e.g.%2C%20x86%20or%20ARM).">post</a> on eBPF!</p><p>Once upon a time, GPUs were considered &#8220;ASICs&#8221;, or application specific integrated circuits. Ie chips optimised for a specific task &#8212; in GPU&#8217;s case, rendering <strong>graphics</strong>.</p><p>In order to grok (spoiler alert!) why GPUs have since become used for matrix multiplication, proof-of-work cryptomining, &amp;, making a <a href="https://stockx.com/en-gb/nvidia">pretty penny</a> on StockX, we need to go back to their ASIC roots. </p><div><hr></div><p><em>** Buckle in, as we&#8217;re about to tackle comp graphics, a rather gnarly (but fun!) topic **</em></p><p>Your computer screen&#8217;s display is made up of minute points of illumination known as &#8220;pixels&#8221; &#8212; aka &#8220;<strong>pi</strong>cture <strong>el</strong>ement<strong>s</strong>&#8221;. Colour, coat &amp; shade these little guys &amp; you &#8220;render&#8221; graphics. Do so with great detail and dynamism, and you generate something as breathtaking as <a href="https://zeldauniverse.net/features/the-10-most-beautiful-locations-in-breath-of-the-wild/#:~:text=more%20peaceful%20place.-,4.%20TALONTO%20PEAK,-There%20are%20many">BOTW</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hjMi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hjMi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hjMi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hjMi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hjMi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hjMi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg" width="886" height="446" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:446,&quot;width&quot;:886,&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_!hjMi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hjMi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hjMi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hjMi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac181a42-8b56-4e8a-89f0-b85365925392_886x446.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><figcaption class="image-caption">I&#8217;m admittedly back writing this caption post starting BOTW for the 4th time</figcaption></figure></div><p>A copious amount of work goes into designing what you see above. However, at a very high-level: Computer graphics is the process of converting data (e.g., cartesian coordinates) into images on a computer screen. </p><p>This conversion gets a whole lot more laborious when converting a <em>3D</em> &#8220;scene&#8221; (more on this in a second). Why? Because your computer screen is a <em>2D</em> environment.</p><p>We&#8217;ll focus on 3D graphics rendering as I think it better illustrates the &#8220;graphics pipeline&#8221;. (Also something we&#8217;ll be revisiting A$AP).</p><p>A &#8220;scene&#8221; is a foundational concept in 3D whereby each scene consists of:</p><ul><li><p>3D geometry (ie &#8220;vectors&#8221;).</p></li><li><p>Transformations.</p></li><li><p>Lights.</p></li><li><p>Material Properties.</p></li><li><p>~A Camera / View. </p></li></ul><p>For graphics newcomers I suspect this all seems a little abstruse. To ground what I just said into reality, pick up an object around you.. perhaps a computer mouse? </p><p>Yes, really.. pick it up. </p><p>Hold the mouse close to your face (the &#8220;camera&#8221; in this case), then move it away from you. Note how the object inhabits more of your field of view when close? This is the result of an object (ie the mouse) being &#8220;<strong>transformed</strong>&#8221;.  </p><p>Notice how <strong>light</strong> sources bounce off of the mouse when you hold it at various angles?</p><p>Ok, now pick up something else, perhaps your keyboar..efouvwvrrnibtv (I jest!).</p><p>Notice how light sources bounce differently off of your keyboard vs. mouse? This is due to their respective <strong>materials</strong>.  </p><p>If we want to render images on computer screens that <em>look</em> 3D, these images need comparable properties (light, materials, etc) &amp; to exhibit similar behaviours (shadow casting, light refraction, etc).</p><p>For those of you that write code, below is some JavaScript I wrote (TQ three.js) to render <a href="https://mack.work/cube.html">this</a> cube. Note the creation of a &#8220;scene&#8221; with some geometric points, a transformation, some lighting, etc.</p><p><em>** To be clear &#8212; you do not need to understand this code to understand computer graphics! **</em> </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y4UA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y4UA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png 424w, https://substackcdn.com/image/fetch/$s_!y4UA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png 848w, https://substackcdn.com/image/fetch/$s_!y4UA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png 1272w, https://substackcdn.com/image/fetch/$s_!y4UA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y4UA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png" width="1456" height="1475" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1475,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:760224,&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_!y4UA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png 424w, https://substackcdn.com/image/fetch/$s_!y4UA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png 848w, https://substackcdn.com/image/fetch/$s_!y4UA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.png 1272w, https://substackcdn.com/image/fetch/$s_!y4UA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F534f8434-d2ca-4993-9802-014ff8419df2_1840x1864.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">thanks to ray.so for the pretty code display</figcaption></figure></div><p>Ok, so we know what a 3D scene is comprised of &amp; why. How does this scene get converted into the aforementioned 2D image? </p><p><em>** Yes, that&#8217;s right <a href="https://www.nvidia.com/en-gb/about-nvidia/board-of-directors/jensen-huang/">Jensen</a>, via the &#8220;graphics pipeline&#8221;! **</em></p><p>Graphics pipelines vary. However, at a very high-level, what happens here is:</p><ul><li><p>We first create this 3D scene via a 3D creation application such as <a href="https://mack.work/pokemon_yellow">Godot</a> (my favourite piece of software on this here earth!). We then export this 3D scene in an appropriate file format, e.g., .<a href="https://www.threekit.com/blog/gltf-everything-you-need-to-know#:~:text=is%20using%20it.-,What%20is%20glTF%3F,-The%20GL%20Transmission">glTF</a>.</p></li><li><p>We then pass this file (ie data) from our CPU to our GPU. This data is an input into the graphics pipeline. This pipeline is a chain of functions (aka &#8220;shaders&#8221;) that are executed by the GPU. </p></li><li><p>These functions ultimately &#8220;draw&#8221; (ie place, colour and shade) pixels on a screen that represent the supplied 3D scene.<br></p></li></ul><blockquote><p><strong>Technical Detail: </strong>functions in programming are exactly the same concept that you learned in math. They (typically) receive data (arguments), do something with this data (e.g., add two integers together) and &#8220;return&#8221; a result.</p></blockquote><p><br>There are <em><a href="https://www.samsung.com/africa_en/tvs/tv-buying-guide/what-is-8k-tv/#:~:text=An%208K%20TV%20is%20a,resolution%20of%20about%208%2C000%20pixels.">a lot</a></em> of pixels to draw on modern high-resolution screens. </p><p>To make things worse, modern content (think a YouTube video) is often rendered at 60 frames per second &#8212; meaning all of those pixels have to be re-drawn 60 times a second. </p><p>Suddenly, CPUs in all their general-purpose, serialisable goodness seem a little.. inefficient? </p><p><strong>G</strong>raphics <strong>P</strong>rocessing <strong>U</strong>nits were designed to do something about this. </p><p>Whilst modern CPUs may have something to the tune of 10 general-purpose cores (remember, mini-CPUs), modern GPUs like Nvidia&#8217;s GeForce GTX 1080 have <strong>2560 specialised </strong>cores<strong> </strong>(!). <br></p><blockquote><p><strong>Technical Detail: </strong>These cores have less general-purpose instruction sets to those present in CPUs. They&#8217;re &#8220;specialised&#8221; for specific, graphics-based, operations. </p></blockquote><p><br>With this many cores, GPUs can pass many &#8220;pieces&#8221; of 3D geometry (called &#8220;vectors&#8221;) and later in the pipeline, pixels, into multiple instances of our beloved graphics pipeline at once.</p><p><em>** Re-read that previous sentence to make sure it clicks. **</em></p><p>Meaning that GPUs process data (ie vectors &amp; pixels) in a <strong>parallel</strong> manner vs. the serial approach taken by CPUs.<br></p><blockquote><p><strong>Key Point:</strong> CPUs are designed for &#8220;low-latency&#8221; &#8212; doing a single computation as quickly as possible. GPUs are designed for &#8220;high-throughput&#8221; &#8212; doing as many computations as possible. </p></blockquote><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_!RMFM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RMFM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png 424w, https://substackcdn.com/image/fetch/$s_!RMFM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png 848w, https://substackcdn.com/image/fetch/$s_!RMFM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png 1272w, https://substackcdn.com/image/fetch/$s_!RMFM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RMFM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png" width="1076" height="844" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:844,&quot;width&quot;:1076,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:447746,&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_!RMFM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png 424w, https://substackcdn.com/image/fetch/$s_!RMFM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png 848w, https://substackcdn.com/image/fetch/$s_!RMFM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.png 1272w, https://substackcdn.com/image/fetch/$s_!RMFM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F25e062a1-219a-4f6e-8a89-9d62c530bb05_1076x844.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><br></strong>If you&#8217;re interested in learning about the history of GPUs I&#8217;d highly recommend listening to Acquired&#8217;s <a href="https://www.acquired.fm/episodes/nvidia-the-gpu-company-1993-2006">episode</a>(s) on Nvidia. However, I have taken the liberty of bringing you right to the punchline &#8212; high-throughput capabilities are useful for a whole lot more than just graphics rendering &#128551;: </p><p>Proof-of-worked based cryptocurrency mining, matrix multiplication (ie ML), scientific computing, video editing, etc, et al.</p><p>This offloading of specific tasks from CPUs to GPUs (or any specialised hardware for that matter!) is known as <strong>hardware acceleration</strong>. GPUs <em>accelerate</em> graphics rendering as well as certain types of computation. </p><p>&#8230;ok</p><p>If I&#8217;ve done my &#8220;job&#8221; here you should have a high-level understanding of CPUs, GPUs &amp; computer graphics. Not bad! All necessary conduits for truly grokking WebGPU.</p><p><em>** Next up, graphics APIs </em>**</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Just subscribe, maybe? </p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Web<strong><s>GPU</s></strong> is the <em>working name </em>for a <strong>Web API</strong> for <strong><s>accelerated</s></strong> <strong><s>graphics</s></strong> <em>and </em><strong><s>compute</s></strong>.</p><p>Cool, we&#8217;ve picked off a few items here in our definition. Progress. </p><p>We&#8217;re at a point now where we know why our applications would want to communicate with GPUs. Hardware acceleration!</p><p>But, how does this communication happen?</p><p>Graphics APIs, my dear Watson.</p><p><em>** Proceeds to whip out a history textbook **</em> </p><p>The history of the modern graphics pipeline starts in a galaxy far, far away (sorry..) at <a href="https://en.wikipedia.org/wiki/Lucasfilm#:~:text=Lucasfilm%20was%20founded%20by%20filmmaker,the%20Star%20Wars%20Corporation%2C%20Inc.">LucasFilm</a> in 1980. Back then, computer graphics was a particularly onerous process; every GPU model had its own software <strong>(!)</strong> (ie &#8220;drivers&#8221;). <br></p><blockquote><p><strong>Technical Detail: &#8220;</strong>drivers&#8221; expose the GPU&#8217;s capabilities to the operating system in a way the OS understands and expects. The operating system in turn can expose it to applications, using various graphics APIs.</p></blockquote><p><br>This meant that if a developer wanted to get a GPU to execute their graphics pipeline (remember, chain of functions), they would need to know the exact &#8220;instruction set&#8221; for that particular make of GPU. Talk about <em>&#8220;doing things that don&#8217;t scale&#8221;</em>!</p><p>Thankfully, the OpenGL (Khronos Group) &amp; DirectX (Microsoft) &#8220;Graphics APIs&#8221; were released in 1992 + 1995 respectively. </p><p>These Graphics APIs provided a common interface for developers, whereby they  could learn the API&#8217;s specification vs. the specification of a specific GPU driver. The API would then handle an individual GPU&#8217;s idiosyncrasies. <em>C&#8217;est simple!</em></p><p>Alas, the new APIs on the block and their GPU counterparts weren&#8217;t perfect. They only ran the &#8220;fixed-function pipeline&#8221;, or &#8220;FFP&#8221;. I promised many acronyms!</p><p>For once in graphics, the parlance here is semi-informative. &#8220;Fixed Function&#8221; meant that there was a specific.. fixed.. set of functions (e.g., make these pixels look &#8220;foggy&#8221;) exposed to the developer (by these APIs) that they could avail of when rendering graphics. </p><p>Put another way, during the fixed-function pipeline epoch, we didn&#8217;t have truly &#8220;programmable GPUs&#8221;.</p><p>Meaning that developers couldn&#8217;t use GPUs to accelerate arbitrary +/ custom graphics functions that they wrote themselves (aka &#8220;shaders&#8221;). E.g., make these pixels look &#8220;foggy&#8221; based on <em>my specification</em> (ie my code) of foggy.<br></p><blockquote><p><strong>Technical Detail: ~~</strong>Pretty much~~ any function that&#8217;s executed on a GPU is also considered a &#8220;shader&#8221;. Common shaders include vertex shaders, geometry shaders, tesselation control/evaluation shaders and fragment shaders &#8212; this is a topic for another day!</p></blockquote><p><br>Then 2002 came along, and with it, Nvidia unveiling the GeForce FX GPU, a &#8220;fully programmable&#8221; GPU. <br><br>Of course, this innovation primarily initially equated to &#8220;<a href="https://hbr.org/2011/08/henry-ford-never-said-the-fast">faster horses</a>&#8221;. Ie better graphics. </p><p>However, some enterprising folk realised that if they encoded <em>any</em> data they wanted processed <em>as</em> <em>if it was graphics data</em> (remember our 3D scenes?) that they could use these GPUs to accelerate a much broader set of calculations (ie beyond graphics).</p><p><em>C&#8217;est cool, non?</em> </p><p><em>** This is a seminal moment in the history of computing, make sure it clicks **</em> </p><p>Skip forward a wee bit to 2006 and Nvidia released &#8220;CUDA&#8221;. AKA, the succinct, Compute Unified Device Architecture. This was real hat-tip to those using Nvidia GPUs for general-purpose computing. </p><p>Or &#8212; GPGPU, if you will. </p><p>At an embarrassingly ( &#865;&#176; &#860;&#662; &#865;&#176;) high level, CUDA was released as a new API, for <em>a new set</em> of Nvidia GPUs. </p><p>These GPUs had a more general purpose instruction set. Meaning that they could be used for general purpose computing (shocker!), without the complex encoding work I described a few paragraphs back.</p><p>Even better, developers could interface with CUDA in higher-level programming languages like CUDA-C / C++ or.. Fortran.. &#128567;.  </p><p>Ok &#8212; cool, thanks to a spate of innovation in graphics, GPUs were unshackled from their singular use case. Why stop here though?</p><p><em>** We are nearly at WebGPU itself FYI **</em></p><p>Fast-forward to 2011 and Khronos released <strong>&#8220;WebGL&#8221;</strong> (ie &#8220;Web Graphics Library&#8221;) a browser-native, JavaScript API. Unsurprisingly, WebGL is really a thin &#8220;wrapper&#8221; around OpenGL.</p><p>This API ultimately runs &#8220;on top of&#8221; (ie gets converted into) the OpenGL spec when used on macOS / Linus or DirectX on windows.<br></p><blockquote><p><strong>Technical Detail:</strong> &#8220;browser-native&#8221; just means that the API is part of the standard <br>set of APIs that web browsers (e.g., Google Chrome) expose to web developers. </p><p>Meaning that developers don&#8217;t have to &#8220;install&#8221; WebGL like they would install a library like React.  </p></blockquote><p><br>This API enables web developers to perform 2D and 3D rendering (remember, drawing pixels on screens!) within an HTML <code>&lt;canvas&gt;</code> element. </p><p>If you&#8217;re unfamiliar with HTML do not fret, just think of <code>&lt;canvas&gt;</code> as a space on a webpage where graphics can be rendered by a GPU. Pretty simple.</p><p><a href="https://madebyevan.com/webgl-water/">Here&#8217;s</a> an illustration by Figma Co-Founder, Evan Wallace, using WebGL in the early 2000s to showcase realtime water rendering. Press the G key on your keyboard when in the demo &#128526; </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Gn8Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png 424w, https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png 848w, https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png 1272w, https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png" width="1456" height="1059" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1059,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1722461,&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_!Gn8Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png 424w, https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png 848w, https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.png 1272w, https://substackcdn.com/image/fetch/$s_!Gn8Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60b013b9-dffc-45f9-a176-359b1b6eb432_1600x1164.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">Notice the ball shadow, the ripples in the water, etc., all rendered by the graphics pipeline!</figcaption></figure></div><p>Ok &#8212; so as of 2011, GPU APIs are also present in web browsers. Rejoice! </p><p>However, note that there&#8217;s not much chat about WebGL for the &#8220;GPGPU&#8221; use case. Perhaps there&#8217;s room for a new.. <strong>GPU</strong> API for the <strong>Web</strong>..?</p><p><em>** If you&#8217;ve continued reading this far, fair play &amp;.. sorry? **</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">WebPlsSubscribe?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Web<strong><s>GPU</s></strong> is the <em>working name </em>for a <strong><s>Web API</s></strong> for <strong><s>accelerated</s></strong> <strong><s>graphics</s></strong> <em>and </em><strong><s>compute</s></strong>.</p><p>As one might expect in an industry that lionises being &#8220;high-throughput&#8221;, further progress wasn&#8217;t too far away.</p><p>Outside of the web in 2013, <a href="https://www.amd.com/en">AMD</a> began developing &#8220;Mantle&#8221;. This graphics API espoused even &#8220;lower-level&#8221; access to modern GPUs (hence, greater performance).</p><p>Unfortunately, to cut a long-story-short, Mantle&#8217;s public development was discontinued 2 years after its first breath in 2015. However, they graciously (hmm..) donated the API to the Khronos Group in 2016. </p><p>This donation led to the release of &#8220;<a href="https://www.vulkan.org/">Vulkan</a>&#8221; by Khronos. As one would expect, Vulkan exposes Mantle&#8217;s low-level GPU access, but the API also offers:</p><ul><li><p>A single API for both desktop and mobile graphics devices; whereas previously these platforms were split between the OpenGL and OpenGL ES (&#8220;embedded systems&#8221;) APIs respectively. </p></li><li><p>Cross-platform compatibility. Vulkan is available on multiple operating systems and devices; where as Direct3D 12 is, as you might expect, only available on Windows/Xbox (boo).</p></li><li><p>Reduced CPU load by offloading (to the GPU) computations traditionally handled by the CPU.</p></li><li><p>A pretty badass, if not a little disconcerting.. new brand identity. <br></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_!nIuD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nIuD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 424w, https://substackcdn.com/image/fetch/$s_!nIuD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 848w, https://substackcdn.com/image/fetch/$s_!nIuD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!nIuD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nIuD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg" width="840" height="521" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:521,&quot;width&quot;:840,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Vulkan graphics API receives major 1.1 update - Android Authority&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="Vulkan graphics API receives major 1.1 update - Android Authority" title="Vulkan graphics API receives major 1.1 update - Android Authority" srcset="https://substackcdn.com/image/fetch/$s_!nIuD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 424w, https://substackcdn.com/image/fetch/$s_!nIuD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 848w, https://substackcdn.com/image/fetch/$s_!nIuD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!nIuD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbff5e7d-75b4-4c13-9c8a-6c81441ae49b_840x521.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em><br></em>In.. parallel.. (ha!) with Vulkan, Microsoft didn&#8217;t sit back idly &#8212; they released <a href="https://learn.microsoft.com/en-us/windows/win32/direct3d12/direct3d-12-graphics">Direct3D 12</a> in 2015. Apple, unwilling to be left out, also joined in the modern GPU API fray in 2014 avec &#8220;<a href="https://developer.apple.com/metal/">Metal</a>&#8221;.  </p><p><em>** What does this have to do with WebGPU you may be asking yourself? Fair.. **</em></p><p>Well, as I said, WebGL didn&#8217;t exactly orient itself towards the GPGPU use case. Why, <a href="https://www.collinsdictionary.com/dictionary/english/retrophiliac">retrophilia</a>..? WebGPU on the other hand, has first-class support for performing general purpose computations on the GPU.</p><p>WebGL also doesn&#8217;t offer many of the modern features that native solutions, a la Vulkan, provide. How so? </p><p>Well, WebGL is broadly a thin &#8220;wrapper&#8221; (ie a similar spec) based on OpenGL 1.0 (released in 1992), which itself, traces back to Silicon Graphics&#8217; &#8220;IRIS GL&#8221; &#8212; released in the 1980s (!). <em>It old</em>.</p><p>Meaning that WebGL isn&#8217;t really built to match the design of modern GPUs, causing GPU &amp; CPU performance issues. This ageing spec also means it&#8217;s difficult to layer WebGL on top of our modern native friends: Vulkan, Direct3D 12, Metal, etc.</p><p>Thus, work on a new Web GPU API began! &amp; with it, a modern, bold, provocative, name.. WebGPU.. </p><p>Whilst WebGPU&#8217;s working name is lacking in some imagination, the API&#8217;s spec and goals most certainly aren&#8217;t. </p><p>Firstly &#8212; <a href="https://surma.dev/things/webgpu/index.html#:~:text=to%20both%20feel-,%E2%80%9Cwebby%E2%80%9D,-and%20to%20comfortably">Surma</a> puts it best, WebGPU feels <em>webby</em> ( <em>/ w&#603;bi /</em> ). Whilst I can&#8217;t exactly provide you with a technical definition here, I agree. WebGPU works in a familiar manner to its Web API <a href="https://developer.mozilla.org/en-US/docs/Web/API">counterparts</a>.</p><p>Generally it&#8217;s viewed that WebGPU is a mixture of Direct3D 12, Metal &amp; Vulkan. So, not only is WebGPU ~~ <em>webby ~~ </em>but it also maps well to native APIs, reducing the aforementioned GPU &amp; CPU performance issues. </p><p>As mentioned, WebGPU also defies WebGL&#8217;s parochialism (bit harsh I know) by exposing two &#8220;pipelines&#8221; (remember, a chain of functions) to web developers &#8212; a &#8220;render pipeline&#8221; and a &#8220;compute pipeline&#8221;.</p><p>Finally, the web as rolled out the red carpet for GPGPU!</p><div><hr></div><p>At this point, we could go deeper into WebGPU&#8217;s spec, tackling its abstractions (logical devices, adapters, etc) but I suspect that this may be overkill for the 3 readers still left&#8230; sorry, I know this was a lengther!<br><br><em>** For those interested in going deeper, Alain Galvan&#8217;s <a href="https://alain.xyz/blog/raw-webgpu">work</a> is the-best-in-the-biz **</em></p><p>So instead, I figured we&#8217;d move onto some final predictions about what trends and applications WebGPU may unlock and/or promulgate:</p><ul><li><p><strong><a href="https://www.zelda.com/breath-of-the-wild/">BOTW</a>-Esque Graphics:</strong> Ironically, the real magic here is when render and compute pipelines are blended. Leveraging the compute pipeline facilitates modern graphics rendering techniques a la <a href="https://developer.nvidia.com/rtx/ray-tracing">ray tracing</a> within the web browser. Expect cool new occlusion / refraction-based UIs.</p></li><li><p><strong>ML in-Browser: </strong>Tensorflow.js (or ONNX.js) <a href="https://www.tensorflow.org/js/demos">provides</a> a bunch of great demos  on why you may want to train a ML model in a web browser. Again, this isn&#8217;t exactly &#8220;novel&#8221; but WebGPU will make the process more performant +/ specific. There&#8217;s also a world where offloading training to your users&#8217; local machine makes sense from a latency, cost + privacy-preserving (long-live <a href="https://whynowtech.substack.com/p/federated-learning">federated learning</a>) perspective. </p></li><li><p><strong>&#8220;Serious Software&#8221;</strong> <strong>in-Browser: </strong>Broadly, serious software (think Blender, Unreal, AE, etc) is OS-native vs. web-native due to its performance requirements. Collaboration flows (as Figma has proven) change entirely when you can afford to be &#8220;multiplayer-first&#8221; (thanks to web browsers). I&#8217;m curious if this creates sufficient breathing room to dethrone the likes of Unity or Autodesk. </p></li><li><p><strong>&#8220;Serious Games&#8221; in-Browser: </strong>there have been numerous <a href="https://stadia.google.com/gg/">false starts</a> in this space and it&#8217;s still very much TBD on the local vs. cloud gaming debate &#8212; perhaps not mutually exclusive! Either way, with WebGPU it&#8217;s far more plausible that there&#8217;s a future where I&#8217;ll be playing The Elder Scrolls with some mates within a web browser. How cool.</p></li><li><p><strong>Browser-OS: </strong>As teased, the browser is increasingly being bestowed with the functionality of native operating systems. Future applications will all be expected to look/work like <a href="https://linear.app/">Linear</a> &#8212; offline mode enabled, multiplayer-first, etc. This trend is being driven by many innovations, WebGPU is a constituent. </p></li></ul><p><em>** WebGPU &#8212; fin **</em></p><div class="pullquote"><p>Once again, I&#8217;d appreciate love +/ lambasting on this <a href="https://twitter.com/alex__mackenzie">post&#8217;s tweet</a> to help get Why Now out into the ether further!</p><p>I&#8217;m at alex@tapestry.vc if you feel like saying hello / trading notes!</p></div>]]></content:encoded></item><item><title><![CDATA[Something Different #2]]></title><description><![CDATA[Hello! Given that ..nothing at all.. has happened over the past week or two I said now would be an objectively rational time to share another update (a la something different). Firstly, some thoughts.]]></description><link>https://whynowtech.substack.com/p/something-different-2</link><guid isPermaLink="false">https://whynowtech.substack.com/p/something-different-2</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Thu, 17 Nov 2022 19:16:29 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0edcee31-4ff9-4b91-873a-f66538f91289_300x168.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello! Given that ..nothing at all.. has happened over the past week or two I said now would be an objectively rational time to share another update (a la <a href="https://whynowtech.substack.com/p/something-different">something different</a>).  </p><p>Firstly, some thoughts. </p><p>This whole thing has been growing much faster than I expected, I&#8217;ve had some time to reflect on the &#8220;why&#8221;. I promise (hope?) this paragraph has not wandered itself into this post as a thinly veiled &#8220;humble brag&#8221;, but rather, as a brief, ~unconventional, take. </p><p>For really the first time, I&#8217;m writing in a purely self-serving way. What primer will I write next? Whatever complex topic I find satiating. When will I release it? Whenever I feel the pull to do so. </p><p>I&#8217;ve found that this mindset has removed all of the (self-inflicted) pressure that comes with running this type of thing. Which has, ironically, made me more consistent. Go forth, and write selfishly!</p><p><em>** Updates. What I&#8217;ve been up to, etc. **</em></p><p>Ok, I will cede to recency bias and give a brief shoutout to the wonderful team at <a href="https://charm.sh/">Charm</a>. A friend mentioned them last Friday + I spent more time than I care to admit last weekend tinkering around with their various CLI libraries.</p><p><a href="https://gist.github.com/alexmackenzie-wx/492c9a7813f4505345ecc335faffab42">Here&#8217;s</a> a shell script I wrote with Charm (well, <a href="https://github.com/charmbracelet/gum">gum</a>) that enables any of you that are new here to subscribe to Why Now. <em>! How convenient !</em> </p><div class="github-gist" data-attrs="{&quot;innerHTML&quot;:&quot;<div id=\&quot;gist119367990\&quot; class=\&quot;gist\&quot;>\n    <div class=\&quot;gist-file\&quot; translate=\&quot;no\&quot;>\n      <div class=\&quot;gist-data\&quot;>\n        <div class=\&quot;js-gist-file-update-container js-task-list-container file-box\&quot;>\n  <div id=\&quot;file-subscribe-sh\&quot; class=\&quot;file my-2\&quot;>\n    \n    <div itemprop=\&quot;text\&quot; class=\&quot;Box-body p-0 blob-wrapper data type-shell  \&quot;>\n\n        \n<div class=\&quot;js-check-bidi js-blob-code-container blob-code-content\&quot;>\n\n  <template class=\&quot;js-file-alert-template\&quot;>\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash flash-warn flash-full d-flex flex-items-center\&quot;>\n  <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path fill-rule=\&quot;evenodd\&quot; d=\&quot;M8.22 1.754a.25.25 0 00-.44 0L1.698 13.132a.25.25 0 00.22.368h12.164a.25.25 0 00.22-.368L8.22 1.754zm-1.763-.707c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0114.082 15H1.918a1.75 1.75 0 01-1.543-2.575L6.457 1.047zM9 11a1 1 0 11-2 0 1 1 0 012 0zm-.25-5.25a.75.75 0 00-1.5 0v2.5a.75.75 0 001.5 0v-2.5z\&quot;></path>\n</svg>\n  \n    <span>\n      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.\n      <a href=\&quot;https://github.co/hiddenchars\&quot; target=\&quot;_blank\&quot;>Learn more about bidirectional Unicode characters</a>\n    </span>\n\n\n  <div data-view-component=\&quot;true\&quot; class=\&quot;flash-action\&quot;>        <a href=\&quot;{{ revealButtonHref }}\&quot; data-view-component=\&quot;true\&quot; class=\&quot;btn-sm btn\&quot;>    Show hidden characters\n</a>\n</div>\n</div></template>\n<template class=\&quot;js-line-alert-template\&quot;>\n  <span aria-label=\&quot;This line has hidden Unicode characters\&quot; data-view-component=\&quot;true\&quot; class=\&quot;line-alert tooltipped tooltipped-e\&quot;>\n    <svg aria-hidden=\&quot;true\&quot; height=\&quot;16\&quot; viewBox=\&quot;0 0 16 16\&quot; version=\&quot;1.1\&quot; width=\&quot;16\&quot; data-view-component=\&quot;true\&quot; class=\&quot;octicon octicon-alert\&quot;>\n    <path fill-rule=\&quot;evenodd\&quot; d=\&quot;M8.22 1.754a.25.25 0 00-.44 0L1.698 13.132a.25.25 0 00.22.368h12.164a.25.25 0 00.22-.368L8.22 1.754zm-1.763-.707c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0114.082 15H1.918a1.75 1.75 0 01-1.543-2.575L6.457 1.047zM9 11a1 1 0 11-2 0 1 1 0 012 0zm-.25-5.25a.75.75 0 00-1.5 0v2.5a.75.75 0 001.5 0v-2.5z\&quot;></path>\n</svg>\n</span></template>\n\n  <table data-hpc class=\&quot;highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file\&quot; data-tab-size=\&quot;8\&quot; data-paste-markdown-skip data-tagsearch-lang=\&quot;Shell\&quot; data-tagsearch-path=\&quot;subscribe.sh\&quot;>\n        <tr>\n          <td id=\&quot;file-subscribe-sh-L1\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;1\&quot;></td>\n          <td id=\&quot;file-subscribe-sh-LC1\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;><span class=\&quot;pl-c\&quot;><span class=\&quot;pl-c\&quot;>#!</span>/bin/sh</span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-subscribe-sh-L2\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;2\&quot;></td>\n          <td id=\&quot;file-subscribe-sh-LC2\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>CHOOSE=<span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>$(</span>gum choose <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>subscribe<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span> <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>follow me on twitter<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span> <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>subscribe<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span> <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>follow me on twitter<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span><span class=\&quot;pl-pds\&quot;>)</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-subscribe-sh-L3\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;3\&quot;></td>\n          <td id=\&quot;file-subscribe-sh-LC3\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>SCOPE=<span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>$(</span>gum input --placeholder <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>reason for subscribing?<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span><span class=\&quot;pl-pds\&quot;>)</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-subscribe-sh-L4\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;4\&quot;></td>\n          <td id=\&quot;file-subscribe-sh-LC4\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>SUMMARY=<span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>$(</span>gum input --placeholder <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>favorite dev tool?<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span><span class=\&quot;pl-pds\&quot;>)</span></span></td>\n        </tr>\n        <tr>\n          <td id=\&quot;file-subscribe-sh-L5\&quot; class=\&quot;blob-num js-line-number js-code-nav-line-number js-blob-rnum\&quot; data-line-number=\&quot;5\&quot;></td>\n          <td id=\&quot;file-subscribe-sh-LC5\&quot; class=\&quot;blob-code blob-code-inner js-file-line\&quot;>gum confirm <span class=\&quot;pl-s\&quot;><span class=\&quot;pl-pds\&quot;>&amp;quot;</span>Subscribe to Why Now? Really?<span class=\&quot;pl-pds\&quot;>&amp;quot;</span></span> <span class=\&quot;pl-k\&quot;>&amp;amp;&amp;amp;</span> open https://whynowtech.substack.com/</td>\n        </tr>\n  </table>\n</div>\n\n\n    </div>\n\n  </div>\n</div>\n\n      </div>\n      <div class=\&quot;gist-meta\&quot;>\n        <a href=\&quot;https://gist.github.com/alexmackenzie-wx/492c9a7813f4505345ecc335faffab42/raw/63ec56eead8a4dfa81406e4dd5227928673f8a1a/subscribe.sh\&quot; style=\&quot;float:right\&quot;>view raw</a>\n        <a href=\&quot;https://gist.github.com/alexmackenzie-wx/492c9a7813f4505345ecc335faffab42#file-subscribe-sh\&quot;>\n          subscribe.sh\n        </a>\n        hosted with &amp;#10084; by <a href=\&quot;https://github.com\&quot;>GitHub</a>\n      </div>\n    </div>\n</div>\n&quot;,&quot;stylesheet&quot;:&quot;https://github.githubassets.com/assets/gist-embed-598610950903.css&quot;}" data-component-name="GitgistToDOM"><link rel="stylesheet" href="https://github.githubassets.com/assets/gist-embed-598610950903.css"><div id="gist119367990" class="gist">
    <div class="gist-file">
      <div class="gist-data">
        <div class="js-gist-file-update-container js-task-list-container file-box">
  <div id="file-subscribe-sh" class="file my-2">
    
    <div itemprop="text" class="Box-body p-0 blob-wrapper data type-shell  ">

        
<div class="js-check-bidi js-blob-code-container blob-code-content">

  
  <div data-view-component="true" class="flash flash-warn flash-full d-flex flex-items-center">
  
    

  
    <span>
      This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      <a href="https://github.co/hiddenchars" target="_blank">Learn more about bidirectional Unicode characters</a>
    </span>


  <div data-view-component="true" class="flash-action">        <a href="{{ revealButtonHref }}" data-view-component="true" class="btn-sm btn">    Show hidden characters
</a>
</div>
</div>

  <span data-view-component="true" class="line-alert tooltipped tooltipped-e">
    
    

</span>

  <table data-hpc="" class="highlight tab-size js-file-line-container js-code-nav-container js-tagsearch-file" data-tab-size="8" data-paste-markdown-skip="" data-tagsearch-lang="Shell" data-tagsearch-path="subscribe.sh">
        <tbody><tr>
          <td id="file-subscribe-sh-L1" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="1"></td>
          <td id="file-subscribe-sh-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-c"><span class="pl-c">#!</span>/bin/sh</span></td>
        </tr>
        <tr>
          <td id="file-subscribe-sh-L2" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="2"></td>
          <td id="file-subscribe-sh-LC2" class="blob-code blob-code-inner js-file-line">CHOOSE=<span class="pl-s"><span class="pl-pds">$(</span>gum choose <span class="pl-s"><span class="pl-pds">"</span>subscribe<span class="pl-pds">"</span></span> <span class="pl-s"><span class="pl-pds">"</span>follow me on twitter<span class="pl-pds">"</span></span> <span class="pl-s"><span class="pl-pds">"</span>subscribe<span class="pl-pds">"</span></span> <span class="pl-s"><span class="pl-pds">"</span>follow me on twitter<span class="pl-pds">"</span></span><span class="pl-pds">)</span></span></td>
        </tr>
        <tr>
          <td id="file-subscribe-sh-L3" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="3"></td>
          <td id="file-subscribe-sh-LC3" class="blob-code blob-code-inner js-file-line">SCOPE=<span class="pl-s"><span class="pl-pds">$(</span>gum input --placeholder <span class="pl-s"><span class="pl-pds">"</span>reason for subscribing?<span class="pl-pds">"</span></span><span class="pl-pds">)</span></span></td>
        </tr>
        <tr>
          <td id="file-subscribe-sh-L4" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="4"></td>
          <td id="file-subscribe-sh-LC4" class="blob-code blob-code-inner js-file-line">SUMMARY=<span class="pl-s"><span class="pl-pds">$(</span>gum input --placeholder <span class="pl-s"><span class="pl-pds">"</span>favorite dev tool?<span class="pl-pds">"</span></span><span class="pl-pds">)</span></span></td>
        </tr>
        <tr>
          <td id="file-subscribe-sh-L5" class="blob-num js-line-number js-code-nav-line-number js-blob-rnum" data-line-number="5"></td>
          <td id="file-subscribe-sh-LC5" class="blob-code blob-code-inner js-file-line">gum confirm <span class="pl-s"><span class="pl-pds">"</span>Subscribe to Why Now? Really?<span class="pl-pds">"</span></span> <span class="pl-k">&amp;&amp;</span> open https://whynowtech.substack.com/</td>
        </tr>
  </tbody></table>
</div>


    </div>

  </div>
</div>

      </div>
      <div class="gist-meta">
        <a href="https://gist.github.com/alexmackenzie-wx/492c9a7813f4505345ecc335faffab42/raw/63ec56eead8a4dfa81406e4dd5227928673f8a1a/subscribe.sh" style="float:right">view raw</a>
        <a href="https://gist.github.com/alexmackenzie-wx/492c9a7813f4505345ecc335faffab42#file-subscribe-sh">
          subscribe.sh
        </a>
        hosted with &#10084; by <a href="https://github.com">GitHub</a>
      </div>
    </div>
</div>
</div><p><br>I also stumbled upon some of Basement&#8217;s <a href="https://lab.basement.studio/experiments/29.circular-fog.js">work</a> (that GameCube throwback &#129394;) who have worked with the likes of Vercel, Scale + MrBeast. This led me down the rabbit hole of <em>finally</em> tinkering around with three.js: <a href="https://mack.work/cube.html">mack.work/cube.html</a>. </p><p>Here&#8217;s the <a href="https://gist.github.com/alexmackenzie-wx/b03689ea017c9e28550368bdb6403ecd">code</a> if, <em>you too</em>, want a rotating cube on your site. </p><p>Modeling in 3D again brought back a bunch of nostalgia &#8212; I used to design YouTube intros using <a href="https://www.maxon.net/en/cinema-4d">Cinema 4D</a> in my early teens. Long ..really cool.. story. So I decided to pick up <a href="https://www.blender.org/">Blender</a> a couple of weeks ago.</p><p><em>** Thankfully, I also spent every other waking moment of my youth playing rugby **</em> </p><p>I am generally a fan of &#8220;serious software&#8221; like Blender, Godot, and After Effects, where you can granularly edit every property, pannel, view, etc. Having a lot of fun (pain) atm modeling a 3D <a href="http://pokemon.fandom.com/wiki/Gengar">Gengar</a> which will replace my rotating cube! &lt;/rip&gt;</p><p>Blender is very much the deep end though. <a href="http://bezel.it">Bezel</a> +/ <a href="https://spline.design/">Spline</a> does a good job of abstracting some of the complexity of 3D away if any of you are interested in dabbling too.</p><p>I, almost contemporaneously, came across Kyle at <a href="https://banana.dev/">Banana.dev</a>&#8217;s <em>&#8220;let&#8217;s build the internet from scratch!&#8221;</em> series of live streams. Highly recommend. </p><p>There&#8217;s something to watching someone iterate on their understanding of a technology live vs. reading a polished primer (guilty) async. </p><p>Hardware folk, I have something for you &#8212; as a result of the above thought, I picked up the <a href="https://www.razer.com/gb-en/streaming-cameras/razer-kiyo">Razor Kiyo Pro</a> and <a href="https://www.razer.com/gb-en/pc/streaming/seiren-family">Razor Seiren X</a> condenser capsule. The condenser mic has a &#8220;super cardioid&#8221; pickup pattern, meaning that it picks up audio from the front, but suppresses audio from the side/back. </p><p>..I also definitely didn&#8217;t pick up a 12&#8221; <a href="https://www.razer.com/gb-en/streaming-accessories/razer-ring-light">ring light</a> which is kind enough to accommodate 192 LEDs.. </p><p>The thought here is that I may emulate Kyle&#8217;s approach &amp; occasionally release a &#8220;raw&#8221; <a href="https://mack.work/">mack.work</a> primer! Figured it may be interesting, if not voyeuristic, for some to see the trials and tribulations (Wikipedia) I go through when learning something new.  </p><p><em>** Why Now ** </em></p><p>Given all of the work/thinking I&#8217;ve been doing in the realm of computer graphics of late, I think it&#8217;d be remiss of me to not tackle WebGPU. </p><p>Here are some of the other technologies I&#8217;ve been looking into recently:</p><ul><li><p>Mongo&#8217;s <strong><a href="https://www.mongodb.com/docs/manual/core/queryable-encryption/">queryable encryption</a></strong>. A bit of a fallacy? Maybe. But, all roads lead to FHE, IMO.</p></li><li><p><strong><a href="https://www.nextflow.io/">Nextflow</a></strong>: a bioinformatics workflow scheduler. *Broadly* similar to Lyft&#8217;s <a href="https://flyte.org/">Flyte</a> (which I <em>believe</em> LatchBio uses). </p></li><li><p><strong><a href="https://www.unison-lang.org/">Unison</a></strong>: a whole new approach to distributed computing. Worth digging into this over an afternoon. I may revisit this in a future primer. </p></li><li><p><strong><a href="https://github.com/Kindelia/manifesto">Kindelia</a>: </strong>an <em>arguably</em> more fundamental model of computation &#8212; Interaction Combinators. This admittedly took me a while to grok but was a lot of fun.</p></li><li><p><strong><a href="https://www.wireguard.com/">Wireguard</a></strong>: something hoping to eat OpenVPN&#8217;s lunch. A simple yet fast and modern VPN that utilizes <strong>state-of-the-art <a href="https://www.wireguard.com/protocol/">cryptography</a>. </strong></p></li></ul><p>I&#8217;d love your thoughts on the above + I&#8217;m always open to suggestions. Feel free to say hello at alex[at]tapestry[dot]vc or on the thread associated with this newsletter.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/something-different-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://whynowtech.substack.com/p/something-different-2/comments"><span>Leave a comment</span></a></p><div><hr></div><p>Thanks for reading as always + lmk what you think of these occasional updates/polls.</p><p>If you have a friend that you think may enjoy reading future primers with a sprinkle of some Irish self-disparagement, I&#8217;d appreciate you sharing this newsletter with them.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">if Subscribe == true: print(&#8220;thanks&#8221;!)</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><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Nix]]></title><description><![CDATA[Containers without containers]]></description><link>https://whynowtech.substack.com/p/nix</link><guid isPermaLink="false">https://whynowtech.substack.com/p/nix</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Fri, 04 Nov 2022 15:30:48 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4osY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="pullquote"><p><em>Wow. &#8220;<a href="https://whynowtech.substack.com/p/something-different">Something Different</a>&#8221;, truly was.. different. Thank you for the kind words &amp; a hello to many new subscribers! To continue to haphazardly ride on the coattails of experimentation, I&#8217;m trying something.. new: I&#8217;d appreciate love +/ lambasting on this <a href="https://twitter.com/alex__mackenzie">post&#8217;s tweet</a> to help get Why Now out into the ether further. </em></p><p><em>As always, I&#8217;m at alex@tapestry.vc should you ever wish to chat.</em></p></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4osY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png 424w, https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png 848w, https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png 1272w, https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png" width="718" height="416.69642857142856" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:845,&quot;width&quot;:1456,&quot;resizeWidth&quot;:718,&quot;bytes&quot;:55888,&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_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png 424w, https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png 848w, https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.png 1272w, https://substackcdn.com/image/fetch/$s_!4osY!,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%2F4fb94035-a6fa-4c23-ba77-093e8690b8b6_2642x1534.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>Stepping on a lego brick, not saving your old Pok&#233;mon game.. software running incorrectly on your machine.. all sources of <em>excruciating</em> pain.</p><p>Cue <em>&#8220;hasn&#8217;t {build tool / package manager} already solved this issue?&#8221;</em> </p><p>In short, somewhat. Docker, Buildpacks, etc., all do a decent job of building + packaging software that can be &#8220;run&#8221; elsewhere. For example, I use Dockerfiles in <a href="https://northflank.com/">Northflank</a> to great effect (plug, et al) if I do say so myself.</p><p>However, a proclamation in software development &#8212; &#8220;works on my machine&#8221; is still necessary; implying that it&#8217;s possible, despite using these tools, that software may indeed, not work on your machine. </p><p>This is where Nix comes in. Well, came in 19 years ago. 10 years Docker&#8217;s senior!</p><p>Nix is <em>notoriously</em> difficult to grok, but in its most reductive form, it&#8217;s a <em>build tool + package manager</em>. More flattering descriptions have extolled the technology with credentials such as &#8220;the future of computing&#8221; or as &#8220;an outrageously underrated technology&#8221;.</p><p>Whatever your Nix headline of choice is, build tools &amp; package managers bridge single-player development to multitenant production &#8212; history would have me believe that any paradigm shift in this realm is worth paying attention to. + If Tobi L&#252;tke <a href="https://twitter.com/tobi/status/1576268144351399936?s=20&amp;t=0wrMxHwR0XQjNb_onEUfqw">compels</a> you to learn about a specific technology, jump on that <em>track</em>.</p><p><em>** Niche tech reference, iykyk **</em> </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Join Tobi in subscribing .. to a newsletter</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Nix enables developers to <em>build</em>: <strong>reproducible</strong>, <strong>declarative,</strong> and <strong>reliable </strong>software. </p><p>To the uninitiated, the above definition will likely be rather abstruse. That&#8217;s ok, I spent many-a-year building software without fully appreciating what was going on under the proverbial hood.</p><p>Alright, let&#8217;s drop our egos and go back to basics. If you&#8217;re intimately (weird!) familiar with how software is built +/ packaged and want to skip to the section on Nix, that&#8217;s cool.</p><p><em>** Turns upright framed picture of <a href="https://nondot.org/~sabre/">Chris Lattner</a> **</em></p><p><em>** I&#8217;m going all in on niche tech references today, sorry ** </em></p><p>Let&#8217;s begin with &#8220;building&#8221; software.</p><p>Applications are often comprised of many files. For example, my <a href="https://mack.work/">blog</a> (thanks Deno) is comprised of a TypeScript file, a JSON file for some config, a &#8220;posts&#8221; folder that contains more &#8220;WIP&#8221; markdown files than I&#8217;d care to admit, etc.</p><p>These files, dear readers, are what&#8217;s known as &#8220;source code&#8221;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!naLw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png 424w, https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png 848w, https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png 1272w, https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png" width="1216" height="316" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/adb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:316,&quot;width&quot;:1216,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34402,&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_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png 424w, https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png 848w, https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.png 1272w, https://substackcdn.com/image/fetch/$s_!naLw!,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%2Fadb8dbfa-bdbd-45ee-84a0-40ebb852b71e_1216x316.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">Gengar is my favorite Pok&#233;mon and wot </figcaption></figure></div><p>Within this source code (the main.ts file specifically), I&#8217;m also &#8220;dependent&#8221; on a bunch of other folks&#8217; code (often called &#8220;packages&#8221;) that <em>I&#8217;ve</em> installed. This collection of third-party code is known as a piece of software&#8217;s <em>dependencies</em>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SKYp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 424w, https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 848w, https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 1272w, https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png" width="1097" height="40" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:40,&quot;width&quot;:1097,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25428,&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_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 424w, https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 848w, https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 1272w, https://substackcdn.com/image/fetch/$s_!SKYp!,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%2F35661cc9-d1bb-4383-840d-c8fa250e0d91_1097x40.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">In main.ts I&#8217;ve installed blog, ga, and redirects &#8220;packages&#8221;</figcaption></figure></div><p> <em>You: &#8220;Why stand on the shoulders of another developer?&#8221;</em> </p><p><em>Alex: &#8220;Why re-invent the wheel?&#8221;</em></p><p>Ok ok. <em>Pourquoi</em> <em>est-ce</em> relevant?</p><p>~~Firstly, build tools take that there source code and convert + bundle it into a format that can be <em>executed</em> by a &#8220;target environment&#8221; (ie ultimately by a CPU). <a href="https://whynowtech.substack.com/p/deno#:~:text=To%20grossly%20oversimplify%2C%20execute%20%3D%20make%20a%20program%20do%20what%20it%E2%80%99s%20supposed%20to%20do.">Remember</a>, &#8220;execute&#8221; = make software do what it&#8217;s intended to do.</p><p>This conversion process is known as &#8220;compilation&#8221; &#8212; source code is <em>compiled</em> into machine code (also called &#8220;binary code&#8221;). You may also hear people refer to this compiled code as an &#8220;executable&#8221;.<br></p><blockquote><p><strong>Technical Detail: </strong>Compiling source code actually creates <em>multiple</em> machine code files called &#8220;object files&#8221; which are then &#8220;linked&#8221; by a.. &#8220;linker&#8221;.. which ultimately creates a <em>single</em> executable file.  </p><p>So &#8212; source code + compilation = object files, object files + linking = single executable. More <a href="https://www.cprogramming.com/compilingandlinking.html">here</a> if you wish to delve into the weeds of it all.   </p></blockquote><p><br><em>** Build tools fin **</em></p><div><hr></div><p>Cool, we now know what&#8217;s required to build software on <em>my</em> computer. Astute readers, if I sent you this executable, would it &#8220;do what it&#8217;s supposed to do&#8221; on <em>your</em> computer? </p><p>Unlikely. Why? Well, I suspect you don&#8217;t have the &#8220;blog&#8221;, &#8220;ga&#8221;, and &#8220;redirects&#8221; packages installed. Remember, our software is <em>dependent</em> on them. </p><p>Even if you do, did you install the same version of those packages as I did? I doubt we&#8217;re even running the same macOS version currently, never mind some comparatively esoteric package.</p><p>Thankfully, a second utility resides within our arsenal &#8212; software &#8220;packaging&#8221; tools. The most famous (infamous?) of which is Docker. </p><p>Packaging tools.. package.. (ie bundle together) your source code alongside the specific (e.g., ga v1.2.3) dependencies it&#8217;s reliant on. Convenient. </p><p>These tools often go a step further and supply additional information that a 3rd party (e.g., a cloud provider) may need in order to correctly <em>build </em>your software<em>.</em></p><p><em>** The line can get a little blurry between build / packaging tools **</em></p><p>I think this packaging is best illustrated via Docker&#8217;s &#8220;Dockerfile&#8221;. Below is one I use within <a href="https://northflank.com/">Northflank</a>. (to deploy a pretty neat twitter scraper &#128526;)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Igig!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png 424w, https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png 848w, https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png 1272w, https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png" width="969" height="558" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:558,&quot;width&quot;:969,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57562,&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_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png 424w, https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png 848w, https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.png 1272w, https://substackcdn.com/image/fetch/$s_!Igig!,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%2Fb147abd4-0d06-4a91-9ebb-5d9b55a2b728_969x558.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>The above Dockerfile is a list of consecutive instructions (each called a &#8220;build step&#8221;) that when followed, compose an &#8220;image&#8221; of your application. </p><p>Think of images as snapshots in time of the &#8220;environment&#8221; (ie source code, file system, dependencies, etc) required to successfully build your software. These images can then be shared with others, and thus, your environment can be <strong>reproduced </strong>by third-parties. </p><p>Or as Peter Fenton rather poetically puts it &#8212; images give us a way to &#8220;program the global computer&#8221;. </p><p><em>** Packaging fin **</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">requirements.txt = a subscription?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Look, Docker undoubtedly deserves the adulation it&#8217;s received. This said, it has some acute flaws that can only be solved by a fundamentally different approach to building and packaging software. Enter the old timer, Nix. </p><p>Let&#8217;s study one such flaw before we delve into Nix itself. As shown above, Dockerfiles contain a set of instructions that build an image. One of these build steps (e.g., RUN pip install..) involves downloading dependencies from an external source called &#8220;pip&#8221;.<br></p><blockquote><p><strong>&#8220;Fun&#8221; Fact: </strong>Pip is a recursive acronym. It stands for &#8220;Pip installs python&#8221;. Because acronyms in tech weren&#8217;t obtuse enough already!</p></blockquote><p><br>Herein lies a problem. What if the dependency being downloaded from this external source has changed (e.g., maybe it&#8217;s been patched!) vs. the same dependency downloaded by another server/computer a week prior? </p><p>In this instance, two computers are ultimately relying on different environments to build software, <strong>despite using the same Dockerfile (!)</strong>. Thus, using Dockerfiles != true reproducibility. </p><p>This is as close to a mic-drop moment as you get in building software. Take a second to internalize it. </p><p><em>** Disclaimer: Yes, I know you can technically use strict dependency pinning in Docker</em> **</p><p><em>** This still doesn&#8217;t entirely solve the problem **</em></p><p>Ok, 6,917 characters later, and Nix&#8217;s &#8220;Why&#8221; is partially clear. Let&#8217;s peek under the hood. </p><p><em>&#8212; A big thanks to <a href="https://www.youtube.com/watch?v=6iVXaqUfHi4&amp;list=PLRGI9KQ3_HP_OFRG6R-p4iFgMSK1t5BHs&amp;index=15">Burke Libbey</a> who has done a bunch of the heavy lifting here! &#8212;</em></p><p>Nix&#8217;s core belief is that the dependencies that a piece of software relies upon should be explicitly stored within a graph database. A simplified version of my blog&#8217;s &#8220;dependency graph&#8221; would look 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_!PUze!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png 424w, https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png 848w, https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png 1272w, https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png" width="1456" height="1128" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1128,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:85049,&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_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png 424w, https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png 848w, https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.png 1272w, https://substackcdn.com/image/fetch/$s_!PUze!,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%2F7b4d7487-46ac-4ec4-850e-5415b3e77575_3208x2485.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>Why? Because without Nix&#8217;s <em>explicit </em>graph (dubbed the &#8220;Nix Store&#8221;!), my blog may be ~unintentionally reliant on unknown dependencies that exist within my system. Given these dependencies are unknown, I wouldn&#8217;t include them in a Dockerfile, and hence, my environment wouldn&#8217;t be accurately reproduced elsewhere. </p><p><em>** We are running out of mics to drop **</em></p><p>The Nix Store is created with three building blocks: 1) Derivations, 2) Sandboxing, and 3), the Nix language.</p><p><strong>1. Derivations: </strong>similar in principle to a Dockerfile. Derivations are files that contain build steps and are used to add a node to the Nix Store. For our &#8220;main.ts&#8221; node above, the build steps (conceptually!) would be: </p><ul><li><p>Point &#8220;ga&#8221; and &#8220;redirects&#8221; to &#8220;blog&#8221;. </p></li><li><p>Point &#8220;blog&#8221; to a new node called &#8220;main.ts&#8221;. </p></li><li><p>Build the &#8220;main.ts&#8221; node.</p></li></ul><p><strong>2. Sandbox: </strong>how derivations are &#8220;enforced&#8221;. Nix creates an isolated environment within your system (limiting network/file access, etc) in order to ensure that when you&#8217;re building a node, you only have access to the dependencies declared in the derivations. No more unintentional dependencies!<br></p><blockquote><p><strong>Technical Detail: </strong>Nix goes as far as using patched versions of compilers and linkers that don't look in default locations (<code>/usr/lib</code>, and so on) for dependencies. Thus creating a truly isolated environment. Pretty cool!</p></blockquote><p><strong><br>Nix language: </strong>is the language used to write these derivation files. Comparable (although considerably more powerful!) to the commands (&#8220;COPY&#8221; / &#8220;RUN&#8221;) used to structure a Dockerfile.</p><p>Let&#8217;s tie this all together:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TIUF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png 424w, https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png 848w, https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png 1272w, https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png" width="1456" height="413" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:413,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:43893,&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_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png 424w, https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png 848w, https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.png 1272w, https://substackcdn.com/image/fetch/$s_!TIUF!,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%2Fc4ed1e6b-935a-4315-9033-524303c4c5e5_3381x958.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>If I&#8217;ve done my job correctly (?), the core tenets + components of Nix should be clear. Now, in order for someone to accurately reproduce your software, all they have to do is install the package from the <a href="https://github.com/NixOS/nixpkgs">Nix Packages</a> registry. (the world's largest repo!)</p><p>I&#8217;m a selfish writer, however, so there&#8217;s a little more <a href="https://towardsdatascience.com/top-8-magic-commands-in-jupyter-notebook-c1582e813560">%magic</a> (niche reference v3) I want to linger on. </p><p>Firstly, each node is added as a unique file path within the Nix Store. Examples:</p><ul><li><p><code>/nix/store/bv6znzsv2qkbcwwa251dx7n5dshz3nr3-zlib-1.2.11/lib/libz.so.1</code></p></li><li><p><code>/nix/store/fg4yq8i8wd08xg3fy58l6q73cjy8hjr2-glibc-2.27/lib/libc.so.6</code></p></li><li><p><code>/nix/store/fg4yq8i8wd08xg3fy58l6q73cjy8hjr2-glibc-2.27/lib/ld-linux-x86-64.so.2</code></p></li></ul><p>The hash (e.g., <code>bv6znzsv2qkbcwwa251dx7n5dshz3nr3)</code> is derived from the derivation file. Remember, the derivation file contains the specific build steps required to build a node. </p><p><a href="https://github.com/alexmackenzie-wx/drv_example/blob/main/.drv">Here&#8217;s </a>an example derivation file. Warning &#8212; they&#8217;re rather gnarly. You don&#8217;t need to understand the contents but you do need to understand that any changes to the derivation file (perhaps an updated dependency?) will result in a different hash. </p><p>This derived hash allows developers to cross-reference with one another whether or not they&#8217;re building a given piece of software (ie a node) within the exact same environment. </p><p>Par example &#8212; two developers may both have Python 3.2.1 installed. However, if one developer&#8217;s Python node&#8217;s path in the Nix Store is: </p><p>&#187; /nix/store/<code>bv6znzsv2qkbcwwa251dx7n5dshz3nr3-python&#8212;3.2.1</code></p><p>and the other&#8217;s is:</p><p>&#187; /nix/store/<code>fg4yq8i8wd08xg3fy58l6q73cjy8hjr2-python-3.2.1</code></p><p>Then it&#8217;s pretty clear that they&#8217;re building Python differently from one another, despite having the same version installed. Smart!</p><p><em>** Nix &#8212; fin **</em></p><div class="pullquote"><p><em>I&#8217;d appreciate love +/ lambasting on this <a href="http://post&#8217;s tweet">post&#8217;s tweet</a> to help get Why Now out into the ether further!</em></p></div><p>To the handful of you likely left, nice work.. and.. sorry? Hopefully, it&#8217;s clear that the explicitness + strictness of Nix allows you to create truly reproducible build environments. </p><p>I should also state that whilst comparing Docker vs. Nix is helpful for explanatory purposes, Docker is a full containerization suite. If anything, these technologies largely complement one another. Have a look into building Docker images with Nix  &#129779;&#127995;&#127908;</p><p>Fancy programming the global computer anyone?</p><p>As always, I&#8217;m at alex@tapestry.vc should you ever wish to chat about Nix &#8212; or perhaps grab a well-pulled pint of Guinness if ever in London! </p><p><strong>Bonus content:</strong></p><ul><li><p>Nix is hard to grok + harder to use. <a href="https://floxdev.com/">Flox</a> is changing that.</p></li><li><p>2022 Nix <a href="https://discourse.nixos.org/t/2022-nix-survey-results/18983">Survey</a>. Thank you, <a href="https://mobile.twitter.com/ronefroni">Ron</a>!</p></li><li><p># Nix based projects (as of Oct &#8216;22) on GitHub:</p><ul><li><p><strong>2964</strong> repos with a default.nix</p></li><li><p><strong>2053</strong> repos with a flake.nix (up from 1718 on 2022-08-01)</p></li><li><p><strong>3147</strong> repos with a shell.nix </p></li></ul></li></ul>]]></content:encoded></item><item><title><![CDATA[Something different]]></title><description><![CDATA[Hello! As I sit in the Irish countryside (home for a couple of weeks) devoid of anything better to do on a Sunday afternoon I said I would try something a little different. Firstly, some updates. I was somehow allowed onto eBPF Summit&#8217;s (virtual) stage. This was a cool experience, as the very first instance of &#8220;Why Now&#8221; was a primer on eBPF. Thanks to those of you who subbed from day one! Talk&#8217;s]]></description><link>https://whynowtech.substack.com/p/something-different</link><guid isPermaLink="false">https://whynowtech.substack.com/p/something-different</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Sun, 09 Oct 2022 18:35:59 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/31a3e38b-9e25-4616-b56c-13e5265fb121_2560x1440.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello! As I sit in the Irish countryside (home for a couple of weeks) devoid of anything better to do on a Sunday afternoon I said I would try something a little different.</p><p>Firstly, some updates. </p><p>I was somehow allowed onto eBPF Summit&#8217;s (virtual) stage. This was a cool experience, as the very first instance of &#8220;Why Now&#8221; was a primer on eBPF. Thanks to those of you who subbed from day one! Talk&#8217;s <a href="https://www.youtube.com/watch?v=2jNCQwgy0fI">here</a>. </p><p><em>** breaks golden rule of not directing readership elsewhere **</em></p><p>Most of my &#8220;dev&#8221; time of late has been within the sublimely crafted walled garden that is the <a href="https://godotengine.org/">Godot</a> game engine. I&#8217;m currently remaking Pokemon Yellow which has been a bunch of fun; the code+commentary can be found on my blog: <a href="https://mack.work/pokemon_yellow">mack.work/pokemon_yellow</a></p><p>Any residual dev time has been spent on learning <a href="https://ziglang.org/">Zig</a> + on tinkering around with <a href="https://docs.manim.community/en/stable/examples.html">Manim</a>. I&#8217;m currently animating some graphs associated with the world of venture investing which I&#8217;ll share on my <a href="https://twitter.com/alex__mackenzie">Twitter</a>. </p><p>Manim is a math animation library created by Grant Sanderson of 3Blue1Brown fame. If you haven&#8217;t frequented his YT channel yet then check out this <a href="https://www.youtube.com/watch?v=aircAruvnKk">primer</a> on neural nets &#8212; you truly won&#8217;t be disappointed. Grant is a big source of inspiration for my technical writing. </p><p><em>** Something different **</em></p><p>Anyway, much like what you&#8217;ve come to expect from these newsletters, I am bloviating. Below I&#8217;m going to share the topics I&#8217;m thinking about tackling next; the thought here is that I won&#8217;t get to all of these areas/technologies but you may wish to explore them on your own accord. </p><p>I&#8217;d love your thoughts on them + I&#8217;m always open to suggestions. Feel free to say hello at alex[at]tapestry[dot]vc or on the thread associated with this newsletter.</p><ul><li><p><strong><a href="https://nixos.org/">Nix</a>: </strong>a build tool + package manager that explicitly defines an application&#8217;s dependencies via a graph database. Tobi Lutke is a <a href="https://twitter.com/tobi/status/1576268144351399936?s=20&amp;t=cCoAAmwLwjYaqr4yObSfxw">fan</a>. </p></li><li><p><strong><a href="https://www.w3.org/TR/webgpu/">WebGPU</a>: </strong>Remember WebGL? A next-gen web GPU API based on Vulkan, Metal, and Direct3D 12. Superb primer by Surma.dev <a href="https://surma.dev/things/webgpu/">here</a>. </p></li><li><p><strong><a href="https://www.deepmind.com/research/highlighted-research/alphafold">AlphaFold</a>: </strong>Honestly I don&#8217;t think AlphaFold&#8217;s receiving enough hype en masse given how profound of an unlock it is. + I know very little about computational biology so this could be fun/humbling.</p></li><li><p><strong><a href="https://aws.amazon.com/ec2/nitro/nitro-enclaves/">Nitro Enclaves</a>: </strong>an isolated compute environment avec some cryptographic attestation. Leveraged by companies like <a href="https://evervault.com/">Evervault</a>.</p></li><li><p><strong><a href="https://godotengine.org/">Godot</a>: </strong>my weapon of choice for game development, not the <a href="https://en.wikipedia.org/wiki/Waiting_for_Godot">play</a>. If you&#8217;re keen to learn about the engine / game dev more broadly I&#8217;m happy to chat also. </p></li><li><p><strong><a href="https://ziglang.org/">Zig</a>: </strong>general-purpose programming language/toolchain. Learning new languages/their data structures is just fun. <a href="https://bun.sh/">Bun</a> is written in Zig, fyi.<br></p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/something-different/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://whynowtech.substack.com/p/something-different/comments"><span>Leave a comment</span></a></p><div><hr></div><p>Thanks for reading as always + lmk what you think of these occasional updates/polls. </p><p><em>If you have a friend that you think may enjoy reading future primers with a sprinkle of some Irish self-disparagement, I&#8217;d appreciate you sharing this newsletter with them (few subs away from 100!) &#187; <a href="http://whynowtech.substack.com">whynowtech.substack.com</a></em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">if Subscribe == true: print(&#8220;thanks&#8221;!)</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[Deno]]></title><description><![CDATA["node_modules, the heaviest object in the universe"]]></description><link>https://whynowtech.substack.com/p/deno</link><guid isPermaLink="false">https://whynowtech.substack.com/p/deno</guid><dc:creator><![CDATA[Alex Mackenzie]]></dc:creator><pubDate>Thu, 22 Sep 2022 17:28:34 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c6a41e50-fedf-46a4-ab18-48ee917d8147_314x160.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Firstly, a thank you for the subscriber uptake and feedback so far. This newsletter has grown a whole lot faster than I expected &amp; has led to some awesome conversations. If you&#8217;re a founder, investor, or Ryan Dahl, feel free to say hello &#187; alex@tapestry.vc </em></p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hClv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:115968,&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_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!hClv!,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%2Fb6c691d4-98db-48f7-8203-e0c6c54cb6ed_1920x1080.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>The theoretical physicist, <a href="https://en.wikipedia.org/wiki/Wolfgang_Pauli">Wolfgang Pauli</a>, is widely attributed for the counter-intuitive critique: <em>&#8220;it&#8217;s not even wrong&#8221;</em>. </p><p>By this, Pauli means that ideas devoid of strong opinions are categorically worse than those ideas that are deemed to be incorrect, or perhaps even offensive, by some. </p><p>I&#8217;ve found this same sentiment to be true for developer tools &#8212; which I&#8217;m sure is exactly what Pauli was indirectly referring to. </p><p>The &#8220;Developer Community&#8221; is known for being particularly opinionated. Make an explicit product decision and you will be simultaneously worshipped and chastised for it. This was perhaps most evident in Python&#8217;s addition of the <a href="https://realpython.com/python-walrus-operator/">Walrus Operator</a><strong>,</strong> whose reception led to the benevolent dictator for life himself stepping down. Team <a href="https://en.wikipedia.org/wiki/Guido_van_Rossum">Guido</a> over here!</p><p>Arguably one of the most opinionated &#8212; particularly due to its lineage &#8212; developer tools of late is a runtime called Deno. This emerging runtime is important not only because I built my personal <a href="https://mack.work/">blog</a> on top of it, but also because it (along with Cloudflare Workers) represents a new paradigm in cloud computing. Deno [Deploy] is an &#8220;<a href="https://deno.com/blog/series-a#:~:text=Deno%20Deploy%20is%20an%20Isolate%20Cloud">Isolate Cloud</a>&#8221;. </p><p>If the <em>Isolate Cloud</em> really is akin to its predecessors, virtual machines &amp; containers, ~VMware &amp; ~Docker, then it&#8217;s likely worth paying some attention to. Let&#8217;s see what the cloud v3.0.0 is all about.  </p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">As Pauli also once said, it&#8217;s <em>not even wrong </em>for you to subscribe below </p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><a href="https://deno.land/">Deno</a> (Dee-no) is defined as a [<strong>batteries included</strong>], <strong>simple</strong>, <strong>modern</strong>, and <strong>secure</strong> <strong>runtime</strong> <strong>[based on web standards] </strong>for <strong>JavaScript</strong>, <strong>TypeScript</strong>, and <strong>WebAssembly</strong> that uses <strong>V8</strong> and is built in <strong>Rust</strong>. </p><p>There&#8217;s a medley of terms and foundational technologies here that we&#8217;re going to need to unpack. But first, one explanation and then some history.</p><p>A &#8220;runtime&#8221; is a piece of software that helps developers create, compile and execute programs. To grossly oversimplify, execute = make a program do what it&#8217;s supposed to do.</p><p>So, let&#8217;s say I&#8217;ve written a JavaScript program called &#8220;grossly.js&#8221; that calculates 1+1 and returns the answer. </p><p>To execute this program I would open up my terminal, type &#8220;deno run grossly.js&#8221;, et voil&#224;, my program will compile, execute and then return 2 (<a href="https://www.reddit.com/r/memes/comments/jgaou1/quick_mafs/">quick mafs</a>).</p><p></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EGCv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 424w, https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 848w, https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 1272w, https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png" width="1456" height="199" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:199,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:42844,&quot;alt&quot;:&quot;&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 424w, https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 848w, https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 1272w, https://substackcdn.com/image/fetch/$s_!EGCv!,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%2F82958322-2b50-4a47-9a8e-0d6dd534fe9b_2062x282.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">1+1 program on the left, deno executing the program on the right.</figcaption></figure></div><div><hr></div><p><em>** A brief history of JavaScript runtimes ** </em></p><p>Initially, JavaScript was really only executed by web browsers. It was a language invented by Brendan Eich &#8212; who also founded Mozilla &amp; Brave! &#8212; to make webpages served by Netscape Navigator &#8220;dynamic&#8221; (ie the webpage changes based on some logic such as a mouse click). </p><p>This was kind of a painintheass.js though as it meant developers had to write their frontend code in JavaScript and their backend (aka server-side) code in another language (PHP, etc). Put simply, it&#8217;s lessofapainintheass.js for developers to reason about their code if it&#8217;s written in one consistent language.</p><p>So, sure enough, server-side runtimes for JavaScript such as the OG <em>Netscape LiveWire Pro </em>emerged to address (and monetize!) this issue. However, these early server-side runtimes were lacking in what many developers considered to be essential features/characteristics such as:</p><ul><li><p>Standard libraries</p></li><li><p>Non-blocking execution</p></li><li><p>Utilizing V8 vs. JVM</p></li></ul><p>Enter our protagonist, <em>Ryan Dahl</em>. </p><p>During JSConf 2009, Dahl <a href="https://www.slideshare.net/AartiParikh/original-slides-from-ryan-dahls-nodejs-intro-talk">shared</a> a new server-side runtime called <a href="https://nodejs.org/en/about/">Node.js</a>. It touted itself as a &#8220;purely evented, <strong>non-blocking</strong> infrastructure to script highly <strong>concurrent</strong> programs&#8221;. </p><blockquote><p><strong>Technical Detail: &#8220;</strong>Non-blocking&#8221; means that whilst some code - perhaps a database query - is waiting for a response (ie still being executed), subsequent code is executed in the meantime. Thus, your program is &#8220;concurrent&#8221; because it&#8217;s executing multiple lines of code at once! </p></blockquote><p>Fast-forward to 2022 &#8212; I promised this would be brief! &#8212; and Node.js is ubiquitous. As a consumer, you likely used an application built on top of Node.js today (a la Uber). With 11m+ developers using Node.js &amp; its concurrent comrades, it&#8217;s hard to miss.</p><p>However, on May 13, 2018 Node.js saw some developer churn in the shape of our protagonist, Ryan Dahl, who had a new <a href="https://www.youtube.com/watch?v=M3BM9TB-8yA&amp;feature=youtu.be">PowerPoint</a> and new idea. <br></p><p><em>** A new runtime has entered the groupchat **<br></em></p><p>Yes, the creator of the Node.js runtime is now building its ~adversary, Deno. This is about as Hollywood as developer tools get &amp; I&#8217;m here for it. Let&#8217;s pick back up our definition, now armed with some history and new domain knowledge. </p><div><hr></div><p><a href="https://deno.land/">Deno</a> (Dee-no) is defined as a [<strong>batteries included</strong>], <strong>simple</strong>, <strong>modern</strong>, and <strong>secure</strong> <strong><s>runtime</s></strong> <strong>[based on web standards] </strong>for <strong><s>JavaScript</s></strong>, <strong>TypeScript</strong>, and <strong>WebAssembly</strong> that uses <strong>V8</strong> and is built in <strong>Rust</strong>. </p><p>Unlike my publishing cadence, I&#8217;m going to stay consistent here and keep tackling the foundational technologies before we delve into the <em>simple</em>, <em>modern,</em> and <em>secure </em>characteristics of Deno. Next candidate, TypeScript.</p><p>TypeScript is what&#8217;s known as a &#8220;superset&#8221; of JavaScript. This means that the language is derived from, but extends (ie does more) JavaScript. </p><p>Without getting too into the weeds here, JavaScript is a &#8220;dynamically typed&#8221; language, whereas TypeScript &#8212; thank you $MSFT! &#8212; is &#8220;statically typed&#8221;. </p><p>In programming languages, <strong>&#8220;</strong>types&#8221; are a set of categories that describe what a value in a program <em>is</em> (ie is it a number, a string, a boolean, etc.), and as a result, what operations can be taken on the value. </p><p>For example, it doesn&#8217;t make sense to multiply (an operation!) two values that are strings (e.g., &#8220;subscribe&#8221; * &#8220;to-my-newsletter&#8221;), but multiplying numbers does. </p><p>Let&#8217;s see what happens when we try to perform a multiplication operation on strings.  <br></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YRpT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 424w, https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 848w, https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 1272w, https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png" width="1456" height="342" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:342,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:149353,&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_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 424w, https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 848w, https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 1272w, https://substackcdn.com/image/fetch/$s_!YRpT!,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%2F8c9c29ec-eee3-4c98-b022-c887a36f2132_2044x480.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><br>That&#8217;s a lotta &#8220;red&#8221; + &#8220;technical jargon&#8221;. What&#8217;s happening here is we&#8217;re running into what&#8217;s known as a <em>TypeError</em>. Our code isn&#8217;t being successfully executed, as string <em>types</em> can&#8217;t be multiplied by one another. </p><p>Remember, JavaScript code is &#8220;dynamically typed&#8221;. This means that developers aren&#8217;t required to explicitly declare the type of a variable (e.g., that &#8220;hello&#8221; is a string) in their code. Why? Because the types of variables in JavaScript are inferred upon execution (hence, dynamic!) by a runtime. </p><p>Whereas in TypeScript, variables lack imagination. A variable needs to be told that it should be a string. <em>Par example:</em> <br></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EXdd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png 424w, https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png 848w, https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png 1272w, https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png" width="1456" height="431" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:431,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:142411,&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_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png 424w, https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png 848w, https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.png 1272w, https://substackcdn.com/image/fetch/$s_!EXdd!,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%2F1e525b70-115d-4443-ab1b-fb29587bfd9d_2046x606.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><br>Why go through the additional effort? Usability. Being explicit about what your code should consist of, and hence, do, ensures it&#8217;s used by you, and others, as intended.</p><p>Back to Deno. </p><p>Deno supports TypeScript &#8220;out of the box&#8221; (ie it just works). Whereas if you want to execute TypeScript with Node.js you have to install a specific software library &amp; do a little more grease work.   </p><p><em>** <s>TypeScript</s> **</em>  </p><div><hr></div><p><a href="https://deno.land/">Deno</a> (Dee-no) is defined as a [<strong>batteries included</strong>], <strong>simple</strong>, <strong>modern</strong>, and <strong>secure</strong> <strong><s>runtime</s> [based on web standards]</strong> for <strong><s>JavaScript</s></strong>, <strong><s>TypeScript</s></strong>, and <strong>WebAssembly</strong> that uses <strong>V8</strong> and is built in <strong>Rust</strong>. </p><p>Ah, WebAssembly, Wasm, the ordained cool kid on the proverbial block. As I <em>very briefly</em> <a href="https://byrnemluke.com/posts/webassembly#:~:text=%F0%9F%92%A1%20You%20write%20code%20in%20chosen%20lang%20(often%20C/C%2B%2B/Rust)%20%E2%86%92%20you%20use%20a%20specific%20compiler%20for%20that%20language%20%E2%86%92%20this%20creates%20a%20.wasm%20file%20which%20contains%20lower%2Dlevel%20bytecode%20%E2%86%92%20this/these%20files%20are%20executed%20via%20a%20browser%27s%20runtime">helped</a> lay out in Luke Byrne&#8217;s canonical <a href="https://byrnemluke.com/posts/webassembly">post</a>, Wasm is a compilation target. What this means is, that a higher-level language (e.g., Go) gets compiled (ie turned into) a format that more closely resembles &#8220;machine code&#8221;. </p><p><em>** Wasm savants lay down your weapons **</em></p><p>Naturally, for a technology to receive this much fanfare, there&#8217;s <em>much</em> more to it. However, this is a rabbit hole for another day. What&#8217;s important to know is that Deno exposes utilities (e.g., a WebAssembly class) that developers can use to execute WebAssembly code.</p><p>To Node.js&#8217; credit, their support for Wasm seems pretty good too.  </p><p> <em>** <s>WebAssembly</s> (kinda)(you&#8217;ll thank me) **</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Wasyouremail.wasm?</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><a href="https://deno.land/">Deno</a> (Dee-no) is defined as a [<strong>batteries included</strong>], <strong>simple</strong>, <strong>modern</strong>, and <strong>secure</strong> <strong><s>runtime</s></strong> <strong>[based on web standards] </strong>for <strong><s>JavaScript</s></strong>, <strong><s>TypeScript</s></strong>, and <strong><s>WebAssembly</s></strong> that uses <strong>V8</strong> and is built in <strong>Rust</strong>.</p><p>V8, as you motor aficionados might expect, is an &#8220;engine&#8221;. You likely benefit from its labor every day when you use web browsers such as Chrome, Brave, Edge (really?), etc. It was released in 2008 with Chrome in order to compile and execute the JavaScript code present in Chrome-served webpages. </p><p>Astute readers &#8212; yes, this engine handles the &#8220;compilation&#8221; and &#8220;execution&#8221; part of our initial runtime definition. </p><p>The compilation step is easy to understand in principle; turn high-level (JavaScript, TypeScript, WebAssembly) code into <em>optimized</em> 1s and 0s. Whilst a crude synopsis, this is all the detail required regarding Deno.</p><p>Execution is due a little more time. Sure, you now have 1s and 0s that your computer understands, but your computer requires some additional help to ensure these 1s and 0s are <em>understood</em> and <em>dealt </em>with (ie executed) in the best way possible.</p><p>Let&#8217;s unpack execution a little further. </p><p><em>** Notably simplistic analogy inbound **</em> </p><p>Imagine opening whatever book you&#8217;re currently reading on its current page. </p><p>You&#8217;ll likely read the text on the page in some order (remember, &#8220;call stack&#8221;), know who the characters mentioned are based on prior pages (remember, &#8220;memory heap&#8221;) and perhaps change your view on how the plot will pan out (remember, &#8220;garbage collection&#8221;).</p><p>How V8 &#8220;executes&#8221; machine code is ..um.. no different. Ok, again, a stretch, but stay with me here and replace your book&#8217;s &#8220;page&#8221; with a compiled JavaScript program (ie some lines of machine code). </p><p>V8 uses a &#8220;call stack&#8221; to prioritize what lines of code are executed when, a &#8220;memory heap&#8221; to store information that can be used subsequently, and a &#8220;garbage collector&#8221; to delete information that&#8217;s no longer relevant/useful.</p><p>Again, the details as they pertain to Deno aren&#8217;t super important here at a first glance, so don&#8217;t stress. All you need to know is that a program (V8) is used to compile JavaScript, TypeScript, and WebAssembly to machine code, and that this same program is then used to ensure the appropriate execution of said machine code.</p><p>We&#8217;ll return to V8 when we delve into the &#8220;Isolate Cloud&#8221;.</p><p><em>** <s>V8</s> ..fait accompli.. **</em></p><div><hr></div><p><a href="https://deno.land/">Deno</a> (Dee-no) is defined as a [<strong>batteries included</strong>], <strong>simple</strong>, <strong>modern</strong>, and <strong>secure</strong> <strong><s>runtime</s></strong> <strong>[based on web standards] </strong>for <strong><s>JavaScript</s></strong>, <strong><s>TypeScript</s></strong>, and <strong><s>WebAssembly</s></strong> that uses <strong><s>V8</s></strong> and is built in <strong>Rust</strong>.</p><p>If you&#8217;ve frequented the vestibules of the WebAssembly FC (football reference not a technical acronym) then there&#8217;s no doubt you&#8217;ve stumbled into the compilation target&#8217;s comrade, Rust. </p><p>Rust, per <a href="https://insights.stackoverflow.com/survey/2021#technology-most-loved-dreaded-and-wanted">Stack Overflow</a>, has been the most popular programming language for 6 years straight. So, we&#8217;ll linger a little here.</p><p>Rust is a statically typed (like TypeScript!) <strong>&#8220;systems&#8221;</strong> programming language. It&#8217;s comparable to lower-level languages such as C++ or Go vs. higher-level abstractions like JavaScript or Python. </p><p>Systems languages (C, C++, Go, Rust, etc.) are generally used to write programs / utilities that will be used by developers to interact with some underlying piece of hardware (think a CPU).  </p><p>For example, V8 itself is written in C++, the Mac operating system is primarily composed of C code, the Python language is written in C <em>(ooh, meta)</em>, and the Deno runtime is.. &#8220;built in Rust&#8221;. </p><p></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e3Xn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 424w, https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 848w, https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 1272w, https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png" width="1456" height="233" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:233,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102465,&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_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 424w, https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 848w, https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 1272w, https://substackcdn.com/image/fetch/$s_!e3Xn!,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%2F4ea75bf7-ab28-4326-913d-bb203a154b9a_2054x328.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Some Rust CoD3 to read at your leisure</figcaption></figure></div><p></p><p>The big difference vs. languages such C++ (aside from its preferential ergonomics!) is that Rust is &#8220;memory safe&#8221;.</p><blockquote><p><strong>Technical Detail: </strong>&#8220;memory safe&#8221; means that information your programs store (e.g., a name in an array) can&#8217;t be improperly accessed or changed. Your stored information (ie memory) is.. safe. With C++ this isn&#8217;t the case.</p></blockquote><p>To put the importance of memory safety into perspective: in 2019 Microsoft <a href="https://msrc-blog.microsoft.com/2019/07/18/we-need-a-safer-systems-programming-language/">estimated</a> that 70% (!) of all security vulnerabilities in their products over the last decade have been due to memory safety issues. </p><p>As it relates to Deno, Rust is a modern language used to build system-level utilities (such as a runtime!) due to its memory safety et al. It&#8217;s the best tool for the job &#8212; you don&#8217;t need to know anything else. </p><p><em>** <s>Rust</s> has been electrolysis&#8217;d!! ha **</em></p><div><hr></div><p><a href="https://deno.land/">Deno</a> (Dee-no) is defined as a [<strong>batteries included</strong>], <strong>simple</strong>, <strong>modern</strong>, and <strong>secure</strong> <strong><s>runtime</s></strong> <strong>[based on web standards] </strong>for <strong><s>JavaScript</s></strong>, <strong><s>TypeScript</s></strong>, and <strong><s>WebAssembly</s></strong> that uses <strong><s>V8</s></strong> and is built in <strong><s>Rust</s></strong>.</p><p>I salute you if you&#8217;ve made it this far. Now that we&#8217;ve laid the technical foundations, let&#8217;s dig into our rather opinionated runtime, Deno.</p><p>What makes Deno &#8220;simple&#8221; is a subjective matter. I would sum up its simplicity as a collection of characteristics:</p><ol><li><p><strong>Web Compatability: </strong>Deno comes packaged with existing &#8220;web standards&#8221; &#8212; ie the same APIs that the browser exposes to frontend developers. Whereas Node.js doesn&#8217;t.</p></li><li><p><strong>Single Executable:</strong> You can build complex websites and contain them within a single file of JavaScript.</p></li><li><p><strong>&#8220;Batteries Included&#8221;: </strong>Deno comes bundled with a number of useful utilities. Want to build a web app? Use their web framework, <a href="https://fresh.deno.dev/">Fresh</a>. Want to format your Fresh code? Use <code>deno fmt</code>. Want to deploy said web app? Use Deno <a href="https://deno.com/deploy">Deploy</a>. Want me to stop? &#8230; fair.</p></li><li><p><strong>Dependency Management</strong>: Deno imports dependencies (ie other people&#8217;s code you&#8217;re using) via a URL import vs. a &#8220;package registry&#8221; like npm. No more node modules / package.json / the &#8220;require()&#8221; syntax &#129394; (those who know, <em>know</em>).</p></li></ol><p><em>** <s>simplicity</s> + <s>web standards</s> + <s>batteries included</s> in one fell swoop **</em></p><p>&#8220;Modern&#8221; is easy. As mentioned already, Deno is unshackled by the technical inertia of Node.js &#8212; the runtime uses/supports new kid on the block technologies: Rust, TypeScript, and WebAssembly. </p><p><em>** <s>modern</s> **</em></p><p>&#8220;Secure&#8221; is deserving of a little more attention. I suspect Pauli would speculate that this is where Deno could..<em> be wrong</em>. </p><p>Deno is secure by default. The runtime requires you to explicitly state what a program&#8217;s allowed to do/access.</p><p>For example, if you have a JavaScript program that wants to use Deno&#8217;s fetch API to make a request over a network, you have to explicitly state that this is allowed. </p><p>For an example of the above example: <code>deno run --allow-net fetch.ts </code>tells Deno to compile and execute the file &#8220;fetch.ts&#8221; and allows (--allow) the file to access the computer&#8217;s network (-net).</p><p><em>** <s>secure</s> --is scratched off the list.ts! ** </em></p><div><hr></div><p><a href="https://deno.land/">Deno</a> (Dee-no) is defined as a <s>[</s><strong><s>batteries included</s></strong><s>]</s>, <strong><s>simple</s></strong>, <strong><s>modern</s></strong>, and <strong><s>secure</s></strong> <strong><s>runtime</s></strong> <strong><s>[based on web standards]</s> </strong>for <strong><s>JavaScript</s></strong>, <strong><s>TypeScript</s></strong>, and <strong><s>WebAssembly</s></strong> that uses <strong><s>V8</s></strong> and is built in <strong><s>Rust</s></strong>.</p><p>Scratching those definitions felt good. You did it, you know what Deno is + a host of some of the most important technologies of the modern web.</p><p>However, those of you with no garbage collection (..good memory..)(..I&#8217;m sorry..) may remember at the beginning of this primer I mentioned <strong>Deno Deploy</strong> being an &#8220;Isolate Cloud&#8221;. <br></p><p><em>** Before we move forward to cloud v3.0.0, consider sharing this primer with a friend? **</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/deno?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://whynowtech.substack.com/p/deno?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p><br>In <a href="https://blog.cloudflare.com/cloud-computing-without-containers/">Cloud Computing Without Containers</a>, Zack Bloom of Cloudflare fame explains that Cloudflare <a href="https://workers.cloudflare.com/">&#8220;Workers&#8221;</a> (their Serverless product) don&#8217;t rely on virtual machines or containers. At the time this was unique vs. serverless competitors such as AWS Lambda. This was kinda a cloud infra equivalent of the proverbial mic drop. </p><blockquote><p><strong>Technical Detail: </strong>&#8220;Serverless&#8221; doesn&#8217;t actually mean <em>no-servers</em>. It&#8217;s really a business model. With serverless, developers don&#8217;t have to rent a specified amount of backend services (ie servers) from their cloud provider. Instead, they dynamically (ie automatically) rent based on their usage.  </p></blockquote><p>Instead, Cloudflare Workers rely on a little something called <strong>V8</strong> (!!) <strong>Isolates</strong> &#8212; a particular ~feature of Chrome&#8217;s V8 engine. It&#8217;s this same technology that Deno Deploy uses to make application deployment an absolute breeze. It nearly feels.. wrong.</p><p><em>..How so?</em></p><p>Isolates allow disparate cloud computing users (ie &#8220;tenants&#8221;) to not only share an operating system (this is what containers enable), but to inherit the same <em>runtime environment</em> (yes, e.g., Deno!) too. </p><p><em>Why does this matter?..</em></p><p>Well, firstly, developers get to think about the cloud infrastructure their code runs on even less than when they use containers. With isolates, ~all they have to think about is writing their application code. </p><p>For context, managing infrastructure is analogous to &#8220;admin&#8221;, y&#8217;don&#8217;t want to do it, you just want to play rugby outside (write code).</p><p>Secondly, isolates are incredibly &#8220;lightweight&#8221;, meaning they take up very little "space&#8221; on a given server. Why? Again, because isolates solely contain application code vs. a bunch of other contexts needed when deploying to containers.</p><p>More space unlocks some rather interesting features for the users of isolate clouds. In Deno Deploy&#8217;s case, every time you deploy some code, Deno Deploy provides an entirely new server to host that code. Then, when you commit some changes to your code and deploy those changes, Deno will persist the old code on the original server <em>and</em> &#8220;spin up&#8221; a new server to host your updated code. </p><p>This makes &#8220;rolling back&#8221; to previous versions of your application (as well as testing) a walk in the park.</p><p>In Cloudflare&#8217;s case, more space&#8482; means that it&#8217;s economical (among other things) for them to make copies of your application code and deploy these copies across their global mesh of servers. As a result, you have a truly global, low latency, application.</p><p><em>! How cool !</em></p><p>So yeah, when someone&#8217;s inevitably bloviating about the &#8220;future of cloud&#8221; think (but never say out loud) &#8220;more space&#8221; and you&#8217;ll likely be able to wade through the technical jargon and land on the same endpoint. Nice work!</p><p><em>** <s>isolate cloud</s> fin **</em></p><div><hr></div><p><em>If you&#8217;ve come this far, thanks for reading! If you have a friend that you&#8217;d like to torture with some &#8220;light&#8221; runtime literature, sharing this post is sincerely appreciated.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://whynowtech.substack.com/p/ebpf?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&amp;token=eyJ1c2VyX2lkIjoyMDQwOTQzMiwiaWF0IjoxNjU2MTY2MTA4LCJpc3MiOiJwdWItODk0ODUwIiwic3ViIjoicG9zdC1yZWFjdGlvbiJ9.PuDAkstAoyy1y1DeIeU2lfYP7KOK0CfOYCMymAq1gVA&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://whynowtech.substack.com/p/ebpf?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&amp;token=eyJ1c2VyX2lkIjoyMDQwOTQzMiwiaWF0IjoxNjU2MTY2MTA4LCJpc3MiOiJwdWItODk0ODUwIiwic3ViIjoicG9zdC1yZWFjdGlvbiJ9.PuDAkstAoyy1y1DeIeU2lfYP7KOK0CfOYCMymAq1gVA"><span>Share</span></a></p><p><em>If you&#8217;re building the cloud v4.0.0 <strong>or</strong> just interested in sparring on new technologies more broadly I&#8217;d love to talk with you / grab coffee if you&#8217;re in London &gt;&gt; alex@tapestry.vc</em></p>]]></content:encoded></item></channel></rss>