<?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[Equals Engineering]]></title><description><![CDATA[Engineering at Equals.]]></description><link>https://engineering.equals.com</link><image><url>https://substackcdn.com/image/fetch/$s_!o9kH!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86fa9fe8-f914-477a-8323-0feb2e13aa11_256x256.png</url><title>Equals Engineering</title><link>https://engineering.equals.com</link></image><generator>Substack</generator><lastBuildDate>Sun, 05 Apr 2026 20:02:47 GMT</lastBuildDate><atom:link href="https://engineering.equals.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Jamie Osler]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[equalsengineering@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[equalsengineering@substack.com]]></itunes:email><itunes:name><![CDATA[Jamie Osler]]></itunes:name></itunes:owner><itunes:author><![CDATA[Jamie Osler]]></itunes:author><googleplay:owner><![CDATA[equalsengineering@substack.com]]></googleplay:owner><googleplay:email><![CDATA[equalsengineering@substack.com]]></googleplay:email><googleplay:author><![CDATA[Jamie Osler]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Understanding systems]]></title><description><![CDATA[thinking before writing]]></description><link>https://engineering.equals.com/p/understanding-systems</link><guid isPermaLink="false">https://engineering.equals.com/p/understanding-systems</guid><dc:creator><![CDATA[Jamie Osler]]></dc:creator><pubDate>Tue, 12 Nov 2024 17:23:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!58vu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!58vu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!58vu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png 424w, https://substackcdn.com/image/fetch/$s_!58vu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png 848w, https://substackcdn.com/image/fetch/$s_!58vu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png 1272w, https://substackcdn.com/image/fetch/$s_!58vu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!58vu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png" width="1456" height="821" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:821,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:43685,&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_!58vu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png 424w, https://substackcdn.com/image/fetch/$s_!58vu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png 848w, https://substackcdn.com/image/fetch/$s_!58vu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.png 1272w, https://substackcdn.com/image/fetch/$s_!58vu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcdc79c3-f3ee-4b39-abe4-dbd13a70e096_2568x1448.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>When faced with a bug or feature request, there&#8217;s often pressure to start coding immediately. We&#8217;ve found this approach frequently leads to superficial solutions that don&#8217;t address root causes. Instead, at Equals we invest time in building a comprehensive mental model of the problem and related systems.</p><p>If we don&#8217;t have a complete understanding, we make changes that do not address the root cause of the issue, or end up modeling the solution incorrectly. This results in further issues; edge cases we didn&#8217;t expect, new symptoms of the same underlying problem. By taking the time to understand the issue, our systems evolve in a better direction over time, building elegant and maintainable solutions with fewer side effects and bugs.</p><h4>Understand the system as designed</h4><p>Before making changes, we strive to understand the original intention behind the existing code:</p><ul><li><p>What specific problem was the code trying to solve?</p></li><li><p>What was the intended technical design and architecture?</p></li><li><p>What product constraints or assumptions influenced the current implementation? Were they correct?</p></li></ul><p>The need to do this speaks to the importance of clear documentation; at Equals we favor writing down our plans, and committing our investigations into words stored in our ticketing / work log system.</p><p>In understanding the intention behind code, we can question whether those intentions are correct <em>today</em> for the change we want to make. Perhaps we have learnt more about the problem, or we were just wrong in an assumption to begin with. <strong>We embrace changing decisions when we have more information.</strong></p><h4>Understand the actual system</h4><p>Next, we strive to understand the data modeling in our current system. If our data modeling does not match the problem, then there&#8217;s always conflict in our system as <em>built</em> vs the system as <em>desired</em>.</p><p>Again, <strong>extensive writing as we explore a system is crucial</strong>, and having a whiteboard  to scribble our abstract understanding on to is very handy.</p><blockquote><p>One technique I find particularly handy is to search for any conditional statements, and plot those as points on my whiteboard flow diagram. What does the data look like each time we branch?</p></blockquote><p>We ask these questions:</p><ul><li><p>What are the core entities?</p></li><li><p>How are these entities related?</p></li><li><p>Does our current data model accurately represent these entities and relationships?</p></li><li><p>Are there inconsistencies or redundancies in our data model? </p></li><li><p>How does data and control flow through the system?</p></li><li><p>What are the key algorithms and data structures?</p></li><li><p>How do different components interact?</p></li><li><p>Are there discrepancies between the intended design and the actual implementation?</p></li></ul><p>We also need to understand how the system operates while running; this involves thinking about how state moves through the system and is updated. This is hard to capture - our brains only have a certain size of context window.</p><p>System observability is key to this. We invest in traditional observability mechanisms (events, metrics, and logs), but also in tooling for hands-on debugging of particular issues. Spreadsheet workbooks can be constructed in ~infinite different forms, and being able to explore the state of a live spreadsheet is incredibly important.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Building a High Performance Spreadsheet in the Browser]]></title><description><![CDATA[Spreadsheets are easy. You're a decent engineer, you could probably hack one together over a weekend, right? Turns out that rectangles are hard.]]></description><link>https://engineering.equals.com/p/building-a-high-performance-spreadsheet</link><guid isPermaLink="false">https://engineering.equals.com/p/building-a-high-performance-spreadsheet</guid><dc:creator><![CDATA[Mike Stewart]]></dc:creator><pubDate>Tue, 12 Nov 2024 17:00:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1ik8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This post originally appeared on </em><a href="https://wrap-text.equals.com/">Wrap Text by Equals</a><em>.</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_!1ik8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1ik8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg 424w, https://substackcdn.com/image/fetch/$s_!1ik8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg 848w, https://substackcdn.com/image/fetch/$s_!1ik8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!1ik8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1ik8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg" width="1456" height="839" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:839,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:60923,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!1ik8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg 424w, https://substackcdn.com/image/fetch/$s_!1ik8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg 848w, https://substackcdn.com/image/fetch/$s_!1ik8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!1ik8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa17caee3-91e1-4532-a28b-488c9d3b492d_1600x922.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>Spreadsheets are easy. You're a decent engineer; you could probably hack one together over a weekend, right?</p><p>The truth is, you probably could&#8212;bunch of cells, user edits, a little parsing and formula evaluation, maybe a dependency graph. But building a production-quality spreadsheet designed to operate on <a href="https://equals.com/integrations/postgres/?ref=wraptext.equals.com">database-scale data volumes</a> is a little harder.</p><p>Even simple concepts, like keeping track of some coloured rectangles, become nontrivial once you want to start squeezing out the performance limits of the browser environment.</p><h2>Rectangles Are Hard</h2><p>Obviously, a spreadsheet isn't just composed of simple concepts; it's actually a full compiler and virtual machine for the most popular programming environment on the planet: the <em><strong>Excel Implicit Underdefined Formula Language</strong></em>. (The only programming language with active users in the hundreds of millions&#8212;and a functional language, too. Look on with envy, Haskell.)</p><p>But recently, it was one of the "simple" spreadsheet concepts, <em>Formats, </em>that ended up causing a performance bottleneck&#8212;and also providing an interesting journey for our team through the intersection of product engineering and computer science.</p><p>Before getting to the problem, though&#8212;let's clarify what we mean by <em>Formats.</em></p><p>The word might conjure up colours, bold text, etc. It involves that, but beyond the cosmetic, the <em><strong>EIUFL </strong></em>adds some more fun and semantically meaningful concepts into that bucket.</p><p>Think of how you can mark ranges in a spreadsheet as being plaintext, number, currency, or date:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KAHy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KAHy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg 424w, https://substackcdn.com/image/fetch/$s_!KAHy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg 848w, https://substackcdn.com/image/fetch/$s_!KAHy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!KAHy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KAHy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg" width="1456" height="792" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:792,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81730,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!KAHy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg 424w, https://substackcdn.com/image/fetch/$s_!KAHy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg 848w, https://substackcdn.com/image/fetch/$s_!KAHy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!KAHy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a0e4b44-d03e-49bb-877b-ea5392110eac_1600x870.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>That's essentially a layer of "runtime type information" which can be set manually by a user per-cell or across wide ranges, but also dynamically changes and propagates every time you edit a sheet.</p><blockquote><p>Where most pedestrian programming languages are content for every value to have a type, the EIUFL is a little more creative: every value has two independent runtime types.<br><br>There's the "bare" result of a formula expression (which maps roughly to the number, string, etc., primitive types you're used to from any language), plus the format-based runtime type, which applies on a cell level.<br><br>Naturally, both of these types interact in subtle ways when you're actually running the sheet. The EIUFL likes to keep things interesting.</p></blockquote><h2>The User Problem</h2><p>So, how did these simple <em>Formats </em>cause problems?</p><p>We'd been aware for a while of some examples of folks running into slowness on larger workbooks. These were generally power users; in fact, one of the most affected was our own Head of Finance, Chris, who naturally builds all of his analyses on Equals. As he built out larger and more complex models, we saw a steady decline in performance across a wide range of operations.</p><p>Pulling out our performance analysis tools and diving in, a recurrent theme arose: some of the most widespread slowness wasn't coming from the actual formula calculations, ingestion of large amounts of data, or any of the "hard problems" we knew we'd have to tackle; it was coming from accesses to the <em>Formats </em>system.</p><p>How come? I'll lay out the historical journey of <em>Format</em> data structures as it evolved over time from prototype to production, and by the end, I'm betting you'll be able to guess.</p><ul><li><p><strong>Proof of concept, early 2021:</strong> The first version stored per-cell metadata for everything&#8212;the cosmetic stuff, the wacky runtime types, etc. This works! Until it doesn't. It's really common for a spreadsheet power user to select entire rows and columns&#8212;which correspond to large areas of cells&#8212;and make changes to all of it. With larger datasets, this resulted in a pretty classic write-fan-out problem as every cell needed to be updated&#8212;not something you want to have to deal with on a user click.</p></li><li><p><strong>Beta launch, mid-2021:</strong> A mitigation on that was to store either per-cell, per-row, or per-column data&#8212;so if you changed a whole column, we just made one write rather than a bunch. This saves work in some special cases, but if the write doesn't cover a whole row/column, you're out of luck&#8212;you still have the same write problem.</p></li><li><p><strong>Early 2022:</strong> As the write performance became more problematic, a new approach was tried: using an append-log-based approach, where every write to a range of cells was recorded. Multiple writes could, and did, partially overlap with each other; that was resolved by reader code on a last-write-wins basis.</p></li></ul><p>This last approach optimised for writes over reads and resolved the write problems by allowing for quick writes of ranges of any shape. But as a workbook grew, the read cost mounted steadily over time, resulting in the kind of painful sluggishness that Chris ran into when building his financial models.</p><p>We knew that we could likely optimise our existing code further, add smarter caching and preloading, and maybe squeeze out an improvement.</p><p>But if your data structure is wrong, all the micro-optimisation in the world isn't going to let you scale up to 10x your current data volumes (and beyond). It was time to solve this properly.</p><h2>Getting Into The Weeds</h2><p>At heart, what is this <em>Formats</em> problem, in computer science terms?</p><p>If you abstract out all of the spreadsheet details, it boils down to: <em>"how can we efficiently represent disjoint rectangles in a 2D coordinate space, each with a value associated?"</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_!--gr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!--gr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg 424w, https://substackcdn.com/image/fetch/$s_!--gr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg 848w, https://substackcdn.com/image/fetch/$s_!--gr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!--gr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!--gr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg" width="1456" height="839" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:839,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33234,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!--gr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg 424w, https://substackcdn.com/image/fetch/$s_!--gr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg 848w, https://substackcdn.com/image/fetch/$s_!--gr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!--gr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cc2c030-3af2-47a2-9d07-09cd60227c59_1600x922.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">These different values [100, 200, 300] could be different background colors, runtime types, or any value which can be applied to a range of cells</figcaption></figure></div><p>Where part of what <em>efficiently </em>means here is <em>with the minimal number of rectangles, we</em> don't want to end up with a million tiny rectangles, one for every cell in our spreadsheet:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bQ0Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg" width="1456" height="839" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:839,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:67845,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bQ0Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7a53b1b-bc34-46df-8bcd-d4391e281913_1600x922.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">This is what we don't want&#8212;a bunch of tiny rectangles tiling next to each other, instead of fewer, larger rectangles</figcaption></figure></div><p>So our data structure should:</p><ol><li><p>Represent disjoint rectangles on a 2D space</p></li><li><p>Consolidate them down to the minimum set of rectangles required</p></li><li><p>Have fast reads (lookups by position) as well as fast writes (changes to the rectangle space)</p></li></ol><p>No pressure.</p><p>But I hear you exclaim, gentle reader&#8212;<em>this must be a known computer science problem. </em>So it should already be solved, right?</p><p>In some sense, it is; this is "just" rectilinear computational geometry. And indeed, the problem of partitioning an arbitrary rectilinear polygon into a minimum number of rectangles is a <a href="https://arxiv.org/pdf/0908.3916v1.pdf?ref=wraptext.equals.com">solved one</a>. But real engineering isn't that simple; as we'll see, "solved" doesn't always mean <em><strong>solved</strong></em>.</p><h2>Actual Engineering</h2><p>So what actually worked? Forget computational geometry; you want results.</p><p>What worked in practice ended up having 3 basic elements:</p><p>1) For core storage: we stored the rectangles in-memory as simple JS Objects in Maps keyed by numeric IDs.</p><p>We've learned this many times over, but working with primitive JS objects can be <em><strong>extremely </strong></em>fast if you do it right.</p><p>"In the browser" has a bad reputation in terms of performance, but V8, in particular, is one of the most optimised execution environments on the planet, particularly if you follow some basic principles of keeping objects statically shaped to keep them out of dictionary mode (see <a href="https://www.jayconrod.com/posts/52/a-tour-of-v8-object-representation?ref=wraptext.equals.com">Jay Conrad's excellent "Tour of V8"</a> for an intro on this).</p><p>Along the lines of Norvig's <a href="https://gist.github.com/hellerbarde/2843375?ref=wraptext.equals.com">"Latency Numbers Every Programmer Should Know,"</a> when building, it's been invaluable for us to keep in mind an analogous <em>"latency numbers every JS programmer should know" </em>with some ballparks for working with JS primitives, which are universally faster than engineers expect when onboarding.</p><p>2) For read accesses, we used an R-tree spatial index of all the rectangles. This is a slight denormalization, but well worth it.</p><p>If you're unfamiliar with R-trees, if you have data corresponding to points or rectangles, they're good for fast queries of the form <em>"give me all data intersecting this range." </em>The core concept is fairly simple: you build a tree where every leaf node is one of the rectangles you're storing, and the non-leaf nodes are the minimal bounding boxes containing them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D4vi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D4vi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png 424w, https://substackcdn.com/image/fetch/$s_!D4vi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png 848w, https://substackcdn.com/image/fetch/$s_!D4vi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png 1272w, https://substackcdn.com/image/fetch/$s_!D4vi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D4vi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png" width="800" height="685" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:685,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32784,&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_!D4vi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png 424w, https://substackcdn.com/image/fetch/$s_!D4vi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png 848w, https://substackcdn.com/image/fetch/$s_!D4vi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.png 1272w, https://substackcdn.com/image/fetch/$s_!D4vi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd31fbf5-dd4f-4853-abe5-e0d3a770e487_800x685.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 visualisation of an R-tree, shamelessly copied from Wikipedia</figcaption></figure></div><p>As with every real world data structure, there's quite some tricksiness to make it performant, though.</p><p>We evaluated building our own, as our experience is that most JS libraries are not designed for high-performance&#8212;but ended up using the excellent <a href="https://github.com/mourner/rbush?ref=wraptext.equals.com">rbush</a> library by <a href="https://github.com/mourner?ref=wraptext.equals.com">Volodymyr Agafonkin</a>. (If you're building high-performance javascript apps, it's very much worth taking a look at <a href="https://github.com/mourner?tab=repositories&amp;ref=wraptext.equals.com">his projects</a>&#8212;they're gems of polished craftsmanship in the field of often-underwhelming off-the-shelf data structure libraries to be found on npm.)</p><p>3) For writes: this ended up being the most interesting part.</p><p>Recall that the challenge here was ensuring we would merge together rectangles where possible, to avoid ending up with millions of small ones when a few larger ones would do.</p><p>As mentioned in the last section, from a computer science point of view, this is a <a href="https://arxiv.org/pdf/0908.3916v1.pdf?ref=wraptext.equals.com">"solved problem"</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_!-wt-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-wt-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 424w, https://substackcdn.com/image/fetch/$s_!-wt-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 848w, https://substackcdn.com/image/fetch/$s_!-wt-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 1272w, https://substackcdn.com/image/fetch/$s_!-wt-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-wt-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png" width="822" height="306" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:306,&quot;width&quot;:822,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13414,&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_!-wt-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 424w, https://substackcdn.com/image/fetch/$s_!-wt-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 848w, https://substackcdn.com/image/fetch/$s_!-wt-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 1272w, https://substackcdn.com/image/fetch/$s_!-wt-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87556a1b-ccf4-496a-b44a-0ad4f983b06c_822x306.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p>You take the merged polygon of all the area covered</p></li><li><p>Transform it into an "intersection graph" representation, where the nodes are the possible cuts you could make, with edges connecting cuts that intersect each other</p></li><li><p>Find the maximum independent set of that graph of cuts (which, in layman's terms, will be the biggest set of cuts that don't intersect each other).</p></li></ul><p>Phew! I don't blame you if you need to read that one through a couple of times to digest it.</p><p>We <strong>didn't </strong>do that.</p><p>Why not? A few reasons:</p><ol><li><p>This algorithm gives a guaranteed "perfect pack," but scales with ~O(n<sup>3/2</sup>). That mightn't sound so bad, but compared to an O(n) solution, for 10k inputs that's 100 times slower, and for 1M inputs that's 1000 times slower. We've already learned through hard experience that big-O matters.</p></li><li><p>It wasn't stable: as it throws away the current structure each time to recalculate what's optimal, it can easily result in huge diffs after small perturbations. That's a <em>Bad Thing </em>in practice.</p></li><li><p>Finally, it's complex! The transformation to/from a graph-theoretical representation results in high-complexity code in practice. Maintainability is key.</p></li></ol><p>What <strong>did </strong>we do? We chose a far simpler consolidation algorithm: we repeatedly merge any adjacent rectangles which precisely share an edge and just keep going until we can't merge any more.</p><p>There's a real tradeoff in this&#8212;we're no longer guaranteed a "perfect pack." Since it's a greedy algorithm, it may get stuck in local maxima; you can design pathological inputs of awkwardly interleaved inputs, like the teeth of a key, which it'll fail to merge due to its naivety.</p><p>But on the plus side, its worst-case runtime is only O(n). That pays for a lot of imperfect packings.</p><p>And in practice, we've observed exactly zero pathological situations resulting from this in production, while gaining the benefit of simple code and fast writes.</p><h2>Results?</h2><p>Rolling this out to our users (gradually, via feature flag), we were able to see large spreadsheets that previously had many unusably slow user interactions drop down to very usable interaction latencies. (Still far from perfect due to other issues, but one step at a time.)</p><p>And anecdotally, for our power users who were building large models (like our Head of Finance, Chris), our largest workbooks and templates switched from unusably slow to ... just working as they should.</p><p>Having fast access patterns for this data also allowed us to simplify and optimize several other features built on top (sorting, filtering, <a href="https://equals.com/sql-editor/?ref=wraptext.equals.com">data imports from SQL</a>, etc.), which previously had to hack around the limitations of the old data modeling.</p><h2>Conclusion</h2><p>Every system has limits; at some point, I'm sure we'll have to replace this one too. But based on our projections, it should serve us long enough to scale into the millions of rows of data that we're targeting for the next generation of the app.</p><p>If this sounds like the kind of challenge you'd be interested in taking on&#8212;<a href="https://jobs.ashbyhq.com/equals/522ddbd0-cabf-44b1-84a8-ce272a78fb1b?ref=wraptext.equals.com">come join us.</a></p><div data-component-name="FragmentNodeToDOM"><p>As a very simple example, adding 1 to a date results in another date, while adding 1 to a number results in a number. Once you start chaining values through functions, the semantics start getting more complex.</p></div><div data-component-name="FragmentNodeToDOM"><p>Technically rather than rectangles, I should say "hyperrectangles" since they can happily operate on an N-dimensional space, but I refuse to believe anyone has ever used that term in real life.</p></div>]]></content:encoded></item></channel></rss>