<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Basti Ortiz</title>
    <description>The latest articles on DEV Community by Basti Ortiz (@somedood).</description>
    <link>https://dev.to/somedood</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F108756%2F1bb8b570-520b-4ad9-8a25-ee28c4d04a8d.jpeg</url>
      <title>DEV Community: Basti Ortiz</title>
      <link>https://dev.to/somedood</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/somedood"/>
    <language>en</language>
    <item>
      <title>Coding Agents as a First-Class Consideration in Project Structures</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Mon, 05 Jan 2026 13:00:34 +0000</pubDate>
      <link>https://dev.to/somedood/coding-agents-as-a-first-class-consideration-in-project-structures-2a6b</link>
      <guid>https://dev.to/somedood/coding-agents-as-a-first-class-consideration-in-project-structures-2a6b</guid>
      <description>&lt;p&gt;Coding agents have arguably been the most revolutionary unlock in software engineering since... ever? (Citation needed!) Post-2023, we have lived in a world where probabilistic machines now write much of the world's software for better &lt;em&gt;and&lt;/em&gt; worse.&lt;/p&gt;

&lt;p&gt;But, we're not here to argue if it's for the best. The genie is already out of the bottle, and the most productive way forward is figuring out the best way to use these new tools to ship better (correct!) software faster.&lt;/p&gt;

&lt;h1&gt;
  
  
  Working with Context Windows as the Bottleneck
&lt;/h1&gt;

&lt;p&gt;LLMs have only a limited number of tokens within its operable context window. As the context window fills up, these models tend to degrade in performance. It is therefore in our best (operational and financial) interests to optimize for token efficiency &lt;em&gt;and&lt;/em&gt; effectivity. The last thing we want is to be billed exorbitantly just for sub-par results.&lt;/p&gt;

&lt;p&gt;Many developers swear by the &lt;strong&gt;"40% Rule"&lt;/strong&gt;, where it's been found (anecdotally) that LLMs tend to considerably degrade in output quality past 40% of its context window. In my experience, it hasn't been so bad with the latest frontier models, but it never hurts to live by this principle regardless of the latest advancements.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So, how do we structure a codebase in such a way that optimizes for token efficiency?&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Optimizing for Feature-Localized Context
&lt;/h1&gt;

&lt;p&gt;A while back, I wrote about vertically sliced architectures. Today, we revisit the notion of a feature-driven project structure because it also happens to optimize for the way coding agents explore codebases.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(For the rest of the article, I'll assume that you've already read this.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9" class="crayons-story__hidden-navigation-link"&gt;You're slicing your architecture wrong!&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/somedood" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F108756%2F1bb8b570-520b-4ad9-8a25-ee28c4d04a8d.jpeg" alt="somedood profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/somedood" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Basti Ortiz
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Basti Ortiz
                
              
              &lt;div id="story-author-preview-content-2488928" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/somedood" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F108756%2F1bb8b570-520b-4ad9-8a25-ee28c4d04a8d.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Basti Ortiz&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 15 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9" id="article-link-2488928"&gt;
          You're slicing your architecture wrong!
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/architecture"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;architecture&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devjournal"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devjournal&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;82&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              27&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;p&gt;Stepping into the shoes of a coding agent, the typical workflow involves implementing a single feature at a time (i.e., per context window). At least for now, it's strongly discouraged to do too many unrelated things within a single context window.&lt;/p&gt;

&lt;p&gt;The ideal codebase must therefore be malleable enough such that features can be added &lt;strong&gt;incrementally&lt;/strong&gt; (i.e., a new feature means mostly new code and only a few edits/deletions) and &lt;strong&gt;concurrently&lt;/strong&gt; (i.e., multiple agents/humans can work on the code in isolation without much merge conflicts).&lt;/p&gt;

&lt;p&gt;When a coding agent examines your prompt, it invokes tools that can semantically query (an index of) the codebase, search for key words, and read file contents—typically in that order, too! The result is an end-to-end codemap of the existing infrastructure that would be affected by the proposed new feature, bug fix, deprecation, etc. This is what we see in the &lt;code&gt;PLAN.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Visually, the trace of tool calls resemble a search tree that narrows down from entire subsystems to individual files. Cool, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujx63l7q4957688gpd8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujx63l7q4957688gpd8a.png" alt="An overview of the tree-like traversal of coding agents in a codebase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This exploration doesn't come for free, though! Each tool call dumps intermediate output tokens (e.g., MCP tools, search results, shell invocations, full file reads, etc.) into our already limited context window.&lt;/p&gt;

&lt;p&gt;For instance, tools like Claude Code &lt;em&gt;require&lt;/em&gt; reading the file before writing to it (for good reason!). Before you know it, you're already past the "40% Rule" with fewer tokens to spare for plan refinement—much less for implementation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🗒️ Some LLMs (namely Claude 4+) exhibit &lt;a href="https://platform.claude.com/docs/en/about-claude/models/whats-new-claude-4-5#context-awareness" rel="noopener noreferrer"&gt;"context awareness"&lt;/a&gt;. These models adapt their behavior/effort based on the remaining amount of tokens in their context window. In practice, this means more shortcuts, more sloppy work, and more incomplete features without proper context management.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The usual workaround is to &lt;code&gt;/compact&lt;/code&gt;, &lt;code&gt;/summarize&lt;/code&gt;, or &lt;code&gt;/handoff&lt;/code&gt; before implementing the &lt;code&gt;PLAN.md&lt;/code&gt;; if the &lt;code&gt;PLAN.md&lt;/code&gt; is so good, we may even get away with &lt;code&gt;/clear&lt;/code&gt; entirely. Fancier methods utilize sub-agents for context management. Admittedly, these are often good enough thanks to recent advancements in the state of the art.&lt;/p&gt;

&lt;p&gt;Nevertheless, in a perfect world, we shouldn't have to spend so many tokens in the planning stage alone. Codebase exploration and manipulation shouldn't be so token-hungry. To optimize the explorability of our codebases for humans and AI agents alike, we want...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Highly selective semantic queries that prune out several subsystems of the codebase right off the bat.&lt;/li&gt;
&lt;li&gt;Highly selective keywords &lt;em&gt;within&lt;/em&gt; subsystems that further prune out irrelevant context.&lt;/li&gt;
&lt;li&gt;Highly cohesive and collocated modules for maximum recall within agentic &lt;code&gt;ls&lt;/code&gt; invocations.&lt;/li&gt;
&lt;li&gt;To read &lt;em&gt;only&lt;/em&gt; the right files and &lt;em&gt;only&lt;/em&gt; the absolutely bare minimum context required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Effectively, we are maximizing the &lt;strong&gt;signal-to-noise ratio&lt;/strong&gt; of the exploration stage. The easier it is for coding agents to navigate the codebase, the easier it is to &lt;em&gt;plan&lt;/em&gt; and &lt;em&gt;implement&lt;/em&gt; features for, and the easier it is for humans to review.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Yes, you are still responsible for the code you generate and eventually merge into production!)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Classical Architectures Pessimize Exploration
&lt;/h2&gt;

&lt;p&gt;The opposite of what we want are the classical horizontally-sliced architectures of yester-decade. To reiterate some points from &lt;a href="https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9"&gt;my previous article&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Horizontally sliced project structures violate the collocation principle by scattering snippets of features across separate directories of "services", "controllers", "models", etc. In practice, this means &lt;em&gt;more&lt;/em&gt; &lt;code&gt;ls&lt;/code&gt; tool calls by the coding agent and &lt;em&gt;more&lt;/em&gt; directory jumping by the human.&lt;/li&gt;
&lt;li&gt;Monolithic &lt;code&gt;Service&lt;/code&gt; classes tend to bundle all CRUD operations in one big file even if many of them are unrelated to a particular feature exploration. Invoking the &lt;code&gt;Read&lt;/code&gt; tool on such files thus dumps more code &lt;strong&gt;noise&lt;/strong&gt; than &lt;strong&gt;signal&lt;/strong&gt; into the context window.&lt;/li&gt;
&lt;li&gt;Unless the index of the codebase knows &lt;em&gt;a priori&lt;/em&gt; which subset of lines to &lt;code&gt;Read&lt;/code&gt;, large "service" and "repository" files only pollute the context window with unrelated code—as if the haystack wasn't large enough already.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0kx9l597nhvw2p1musn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0kx9l597nhvw2p1musn.png" alt="Visualization of a horizontally sliced codebase require bloated reads and exploration in the codebase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The situation is exasperated by unit tests and integration tests, where it's easy (and encouraged also for good reason!) to reach thousands of lines. A simple prompt to "write more unit tests" could (very likely!) mean reading the entire test file again.&lt;/p&gt;

&lt;p&gt;Unless cleverly broken up into separate test files, monolithic modules imply even more monolithic test files. We're potentially looking at &lt;em&gt;double&lt;/em&gt; the amount of reads. Again, that's just poor signal-to-noise ratio...&lt;/p&gt;

&lt;h2&gt;
  
  
  How Vertically Sliced Architectures Optimize for Selectivity
&lt;/h2&gt;

&lt;p&gt;What we actually want is a malleable codebase with self-contained feature modules that cohesively implement all of its logic end-to-end. In doing so, files are collocated within a narrow slice of the project structure. Coding agents thus naturally traverse the repository in a few depth-first passes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tovrl9glb3p0qy91vp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tovrl9glb3p0qy91vp0.png" alt="Visualization of how narrow slices in a vertically sliced architecture yield more surgical reads, edits, and incremental changes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The serendipitous consequence is that codebase exploration becomes highly selective by construction and organization. There's no need to explore &lt;code&gt;feature-a/&lt;/code&gt; when the entire end-to-end logic of &lt;code&gt;feature-b/&lt;/code&gt; is already self-contained. File recall almost becomes trivial by virtue of collocation.&lt;/p&gt;

&lt;p&gt;But, we don't have to stop there. Feature modules can still turn for the worse if they degrade to monolithic modules. The solution: modularize the logic (and its tests) even more. Taken to the extreme, we're looking at one function per file such that its associated test file only contains the &lt;code&gt;describe&lt;/code&gt; suites relevant to that specific function only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feature/
├── subsystem/
│   ├── index.ts
│   ├── index.test.ts
│   ├── schema.ts
│   ├── utils.ts
│   └── utils.test.ts
└── subfeature/
    ├── index.ts
    ├── dates.ts
    ├── dates.test.ts
    ├── strings.ts
    └── strings.test.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course I'm &lt;em&gt;not&lt;/em&gt; advocating for this convention because it &lt;em&gt;is&lt;/em&gt; comically harsh, but it's nevertheless illustrative of my overall point about optimizing for narrow end-to-end vertical slices in the name of token-efficient exploration (both for agents and humans alike).&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;A coding agent's behavior resembles a deepening and narrowing search tree. To accommodate coding agents as first-class citizens in our projects (alongside humans), we should structure our codebases accordingly.&lt;/p&gt;

&lt;p&gt;The horizontally sliced codebases of yester-decade will struggle in the agentic era (compared to its vertically sliced counterpart) due to its monolithic conventions and scattered organization of end-to-end logic. Newer codebases should strive to be more feature-driven.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Narrow depth-first slices of the codebase encourage highly selective and cohesive exploration.&lt;/li&gt;
&lt;li&gt;Self-contained modules encourage incremental features (rapid iteration!) and concurrent implementation (no merge conflicts!).&lt;/li&gt;
&lt;li&gt;Modularized logic and collocated files improve recall by eliminating cross-cutting jumps between directories and subsystems.&lt;/li&gt;
&lt;li&gt;Tightly scoped unit tests are more important than ever! Keep your LLMs honest with focused test suites.&lt;/li&gt;
&lt;li&gt;Beware of monolithic &lt;code&gt;Service&lt;/code&gt;-like classes and &lt;code&gt;Repository&lt;/code&gt;-like classes! Avoid dumping too much "inter-feature" logic in the same file except for orchestration code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;And that's how I've been keeping my codebases in check in the agentic era.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Mastering Python's Iteration Protocol: Iterables, Iterators, and Generators</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Sun, 12 Oct 2025 21:44:46 +0000</pubDate>
      <link>https://dev.to/somedood/mastering-pythons-iteration-protocol-iterables-iterators-and-generators-f9e</link>
      <guid>https://dev.to/somedood/mastering-pythons-iteration-protocol-iterables-iterators-and-generators-f9e</guid>
      <description>&lt;p&gt;Over the years, I've received innumerable queries from (mostly) undergraduate computer science students on the difference between &lt;strong&gt;iterables&lt;/strong&gt;, &lt;strong&gt;iterators&lt;/strong&gt;, and &lt;strong&gt;generators&lt;/strong&gt; in programming languages like Python and JavaScript.&lt;/p&gt;

&lt;p&gt;This article consolidates into one master reference all of the answers that I've given and scattered across various internal lecture notes, private Notion documents, Discord servers, and direct messages.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This edition has been adapted for Python idioms. The JavaScript edition, which covers the exact same concepts but with JavaScript's primitives instead, will be coming soon.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Iterator Contract
&lt;/h2&gt;

&lt;p&gt;Our story begins in the &lt;strong&gt;Iterator Contract&lt;/strong&gt;: the very interface that underpins our entire discussion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iterables and &lt;code&gt;__iter__&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Mechanically and contractually, an &lt;a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable" rel="noopener noreferrer"&gt;&lt;code&gt;Iterable&lt;/code&gt;&lt;/a&gt; is any object that implements the &lt;a href="https://docs.python.org/3/reference/datamodel.html#object.__iter__" rel="noopener noreferrer"&gt;&lt;code&gt;__iter__&lt;/code&gt;&lt;/a&gt; dunder method (and can thus be passed as an argument to the builtin &lt;a href="https://docs.python.org/3/library/functions.html#iter" rel="noopener noreferrer"&gt;&lt;code&gt;iter&lt;/code&gt;&lt;/a&gt; function). Semantically, it is any container- or collection-like object (e.g., lists, sets, trees, etc.) that can be "iterated" on.&lt;/p&gt;

&lt;p&gt;The mechanics of "being iterated on" is quite simple. When we pass an object to the &lt;code&gt;iter&lt;/code&gt; function, we expect that it returns an object called the &lt;strong&gt;iterator&lt;/strong&gt;. The iterator is responsible for maintaining the current iteration state of the collection traversal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iterators and &lt;code&gt;__next__&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Mechanically and contractually, an &lt;a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator" rel="noopener noreferrer"&gt;&lt;code&gt;Iterator&lt;/code&gt;&lt;/a&gt; is any object that implements the &lt;a href="https://docs.python.org/3/library/stdtypes.html#iterator.__next__" rel="noopener noreferrer"&gt;&lt;code&gt;__next__&lt;/code&gt;&lt;/a&gt; dunder method (and can thus be passed as an argument to the builtin &lt;a href="https://docs.python.org/3/library/functions.html#next" rel="noopener noreferrer"&gt;&lt;code&gt;next&lt;/code&gt;&lt;/a&gt; function). Semantically, it is an object that keeps track of the current iteration state. (Pedantically, an &lt;code&gt;Iterator&lt;/code&gt; should also implement the &lt;code&gt;Iterable&lt;/code&gt; interface, but this detail is sometimes omitted in practice.)&lt;/p&gt;

&lt;p&gt;As you might expect, the &lt;code&gt;next&lt;/code&gt; function returns the "next" item in the iteration (of all elements in an &lt;code&gt;Iterable&lt;/code&gt; container). You can visualize the &lt;code&gt;Iterator&lt;/code&gt; as a "stream" of objects that you can request from the &lt;code&gt;Iterator&lt;/code&gt; by repeatedly invoking the &lt;code&gt;next&lt;/code&gt; function. When there are no more items left in the &lt;code&gt;Iterator&lt;/code&gt;, the underlying &lt;code&gt;__next__&lt;/code&gt; implementation must raise the &lt;a href="https://docs.python.org/3/library/exceptions.html#StopIteration" rel="noopener noreferrer"&gt;&lt;code&gt;StopIteration&lt;/code&gt;&lt;/a&gt; exception to signal that it has been exhausted.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The `range` object is an `Iterable` container.
&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# We can therefore obtain an `Iterator` over its elements.
&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# We can safely extract the first three items via `next`.
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 0
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 1
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 2
&lt;/span&gt;
&lt;span class="c1"&gt;# But the final invocation will raise an exception!
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# StopIteration
&lt;/span&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Done!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, this is exactly how the &lt;code&gt;for&lt;/code&gt; loop works. The object being iterated on is first passed to the &lt;code&gt;iter&lt;/code&gt; function to obtain an &lt;code&gt;Iterator&lt;/code&gt;. Then, the &lt;code&gt;for&lt;/code&gt; loop invokes &lt;code&gt;next&lt;/code&gt; until it hits the &lt;code&gt;StopIteration&lt;/code&gt; exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This is fancy syntactic sugar for...
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ... a loop that invokes `next` over and over again
# until there are no more elements left.
&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Aside: The Importance of Brand New Independent Instances
&lt;/h3&gt;

&lt;p&gt;I want to emphasize why &lt;code&gt;iter&lt;/code&gt; is typically expected to return a brand &lt;em&gt;new&lt;/em&gt; iterator object. Naturally, when you create an iterator, you expect that the returned instance is its own self-contained iteration state that is independent from other invocations of &lt;code&gt;iter&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A `list` of `str` objects is an `Iterable` out of the box.
&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# These two invocations of `iter` create independent iterators
# that each maintain their own state.
&lt;/span&gt;&lt;span class="n"&gt;first_iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;other_iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;first_iterator&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;other_iterator&lt;/span&gt;

&lt;span class="c1"&gt;# Mutating the iteration state of one iterator should not leak
# into other iterators. They are their own instances!
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 'hello'
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other_iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 'hello'
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 'world'
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other_iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 'world'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are exceptions to this rule, however, which we'll see in the worked examples of the following section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worked Examples
&lt;/h3&gt;

&lt;p&gt;To get a feel around how the Iterator Contract is typically implemented, let's go through a few worked examples.&lt;/p&gt;

&lt;h4&gt;
  
  
  Infinite Counter
&lt;/h4&gt;

&lt;p&gt;Let's implement an infinite counter. It takes in a &lt;code&gt;start&lt;/code&gt; argument which determines where to start counting to infinity from.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InfiniteCounter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt; The starting point of the counter. &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# Implementing the `Iterable` contract
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Observe that we're returning a newly constructed iterator every time.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_InfiniteCounterIterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_InfiniteCounterIterator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;
    Tracks where we are now in the iteration.
    This is our private `Iterator` class.
    &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# We should clone ourselves here so that we don't give out
&lt;/span&gt;        &lt;span class="c1"&gt;# references to our iteration state. Otherwise, it would be
&lt;/span&gt;        &lt;span class="c1"&gt;# possible for multiple variables to "advance" the iterator
&lt;/span&gt;        &lt;span class="c1"&gt;# from different variables. We don't want that!
&lt;/span&gt;        &lt;span class="c1"&gt;#
&lt;/span&gt;        &lt;span class="c1"&gt;# However, it is totally legal to just return `self` here. In fact,
&lt;/span&gt;        &lt;span class="c1"&gt;# many iterators from the standard library simply `return self`
&lt;/span&gt;        &lt;span class="c1"&gt;# (likely to avoid the performance overhead of cloning). As such,
&lt;/span&gt;        &lt;span class="c1"&gt;# we will do the same. We must keep in mind the footguns, though!
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;
        &lt;span class="c1"&gt;# return InfiniteCounterIterator(self.current)
&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__next__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="c1"&gt;# take the first value
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;    &lt;span class="c1"&gt;# advance the iterator
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This is an infinite loop because we never raise `StopIteration`!
&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InfiniteCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 0, 1, 2, 3, ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Singly Linked List
&lt;/h4&gt;

&lt;p&gt;Now let's do the same drill for a basic linked list implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Self&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LinkedList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;_LinkedListIterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_LinkedListIterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__next__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# No more data to yield!
&lt;/span&gt;            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&lt;/span&gt;

        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;         &lt;span class="c1"&gt;# take the current value
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="c1"&gt;# advance the iterator
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generators
&lt;/h2&gt;

&lt;p&gt;Now I'm sure you're thinking that writing explicit &lt;code&gt;Iterator&lt;/code&gt; classes are such a hassle—and you'd be right! In &lt;em&gt;Pythonic&lt;/em&gt; code, we rarely interface with iterators at such a low level. Typically, we use &lt;strong&gt;generators&lt;/strong&gt; and &lt;strong&gt;comprehension syntax&lt;/strong&gt; to make our lives easier.&lt;/p&gt;

&lt;p&gt;Syntactically, a &lt;a href="https://docs.python.org/3/library/collections.abc.html#collections.abc.Generator" rel="noopener noreferrer"&gt;&lt;code&gt;Generator&lt;/code&gt;&lt;/a&gt; is a function that contains at least one &lt;code&gt;yield&lt;/code&gt; keyword. Contractually, it returns an &lt;code&gt;Iterator&lt;/code&gt; that streams the &lt;code&gt;yield&lt;/code&gt;-ed items. Colloquially, it is a "pausable function".&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Generators are best understood by example.
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_hello_world&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;# pause!
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;middle&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;# pause!
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;end&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Generators return iterators!
&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_hello_world&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# 'start'
# 'hello'
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# 'world'
# 'middle'
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# 'end'
# StopIteration!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are also times when it is useful to exhaust an &lt;em&gt;inner&lt;/em&gt; iterator first from within the generator. This is uncommon in practice, but it's handy to know it when you need it! For that, we have the &lt;code&gt;yield from&lt;/code&gt; keyword.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;concat_iterators&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;bonus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Exhaust this iterator first and forward the results.
&lt;/span&gt;    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;
    &lt;span class="c1"&gt;# Then we can exhaust the second iterator after.
&lt;/span&gt;    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;
    &lt;span class="c1"&gt;# We can even yield our own items at any point.
&lt;/span&gt;    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;bonus&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;flatten_iterators&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;iterators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]]):&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt; A fancy way to flatten an iterator of iterators. &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;iterators&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Comprehension Syntax
&lt;/h3&gt;

&lt;p&gt;You may also be familiar with generators through a different syntax: list/set/dictionary comprehensions!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Plain comprehensions are just fancy syntactic sugar over generators!
&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 0
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 2
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 4
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 6
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 8
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# StopIteration!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One common use case for generators is the ability to "aggregate" them into a result or some other collection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# These are functionally equivalent!
&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# The `list` constructor also accepts a `Generator` argument.
# The yielded items will be streamed into the final `list`.
&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The same is true for sets and dictionaries!
&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Internally, you can imagine these "generator consumers" as &lt;code&gt;for&lt;/code&gt; loops that process each element into an aggregation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections.abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;collect_into_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt; This is effectively what the `list` constructor does. &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;collect_into_set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt; This is effectively what the `set` constructor does. &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections.abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;nan&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum_floats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt; This is how the actual `sum` function works! &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;avg_floats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt; Now let&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s get fancy with arithmetic means! &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;

    &lt;span class="c1"&gt;# Let's assume non-empty iterators for simplicity.
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# Alternatively, we may implement this as a running average.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;

&lt;span class="c1"&gt;# Pro tip: you don't need a list comprehension here!
# You can use plain generators to avoid the unnecessary
# memory allocation for the temporary `list`.
&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;float_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum_floats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;float_average&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;avg_floats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simplifying the Worked Examples
&lt;/h3&gt;

&lt;p&gt;Now let's take the worked &lt;code&gt;Iterator&lt;/code&gt; examples from the previous section and see how we can leverage generators to simplify their implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InfiniteCounter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt; The starting point of the counter. &lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Now the infinite loop is more apparent...
&lt;/span&gt;        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Self&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Do you notice the parallels to
&lt;/span&gt;        &lt;span class="c1"&gt;# the explicit iterator version?
&lt;/span&gt;        &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;
            &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LinkedList&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__iter__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Now we can just invoke the inner generator
&lt;/span&gt;        &lt;span class="c1"&gt;# since we've moved the generator to the `Node`.
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Conveniences of &lt;code&gt;itertools&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we've seen how we can build iterator primitives simply out of the &lt;code&gt;next&lt;/code&gt; function and even the &lt;code&gt;yield&lt;/code&gt; keyword, let's explore some of the builtin iterator utilities of the standard library: the &lt;a href="https://docs.python.org/3/library/itertools.html" rel="noopener noreferrer"&gt;&lt;code&gt;itertools&lt;/code&gt;&lt;/a&gt; module.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Infinite Iterators
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 10 11 12 13 ...
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# A B C D A B C D ...
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 10 10 10 10 ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Iterator Combinators
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accumulate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="c1"&gt;# 1 3 6 10 15
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batched&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCDEFG&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# AB CD EF G
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABC&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DEF&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# A B C D E F
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_iterable&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABC&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DEF&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="c1"&gt;# A B C D E F
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pairwise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCDEFG&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# AB BC CD DE EF FG
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zip_longest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ab&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fillvalue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# Aa Bb C- D-
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Combinatoric Iterators
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permutations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# AB AC AD BA BC BD CA CB CD DA DB DC
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;combinations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# AB AC AD BC BD CD
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;combinations_with_replacement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ABCD&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# AA AB AC AD BB BC BD CC CD DD
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recap: what did we learn?
&lt;/h2&gt;

&lt;p&gt;We've discussed a lot, so let's recap on what we learned.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;Iterable&lt;/code&gt; is something you can create a &lt;code&gt;Iterator&lt;/code&gt; from via the builtin &lt;code&gt;iter&lt;/code&gt; function.

&lt;ul&gt;
&lt;li&gt;You can then repeatedly invoke the builtin &lt;code&gt;next&lt;/code&gt; function with an &lt;code&gt;Iterator&lt;/code&gt; as its argument until the &lt;code&gt;StopIteration&lt;/code&gt; exception is raised.&lt;/li&gt;
&lt;li&gt;Internally, a &lt;code&gt;for&lt;/code&gt; loop is just syntactic sugar for advancing an &lt;code&gt;Iterator&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;Generator&lt;/code&gt; functions and the &lt;code&gt;yield&lt;/code&gt; keyword are another syntactic sugar over explicit &lt;code&gt;Iterator&lt;/code&gt; implementations.

&lt;ul&gt;
&lt;li&gt;Generators stream data to the caller via the &lt;code&gt;yield&lt;/code&gt; keyword.&lt;/li&gt;
&lt;li&gt;Generators use the &lt;code&gt;yield from&lt;/code&gt; keyword to exhaust internal iterators first before proceeding.&lt;/li&gt;
&lt;li&gt;Generators are almost like "pausable functions", but not intended for that exact purpose.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;The comprehension syntax is syntactic sugar over explicit simple &lt;code&gt;Generator&lt;/code&gt; implementations.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;The &lt;code&gt;itertools&lt;/code&gt; module is your best friend.&lt;/strong&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There's a common thread here: it's always one syntactic sugar over the other. That's what makes iterables, iterators, and generators so confusing to beginners! To best understand fancy generators, we had to go back to first principles: the &lt;strong&gt;Iterator Contract&lt;/strong&gt;. Everything hinges on that basic design pattern as the primitive for composable utilities.&lt;/p&gt;

&lt;p&gt;Now, a lot of things in computer programming (and computer science in general!) are like that. We face abstractions &lt;em&gt;upon&lt;/em&gt; abstractions &lt;em&gt;upon&lt;/em&gt; abstractions every day. Although it's more convenient to live in higher levels of abstraction, we must never neglect understanding how things &lt;em&gt;really&lt;/em&gt; work at the lowest levels.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The best engineers never shy away from digging deeper.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>computerscience</category>
      <category>programming</category>
    </item>
    <item>
      <title>🔥 Simulating Course Schedules 600x Faster with Web Workers in CourseCast</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Thu, 21 Aug 2025 15:43:06 +0000</pubDate>
      <link>https://dev.to/somedood/simulating-course-schedules-600x-faster-with-web-workers-in-coursecast-41ma</link>
      <guid>https://dev.to/somedood/simulating-course-schedules-600x-faster-with-web-workers-in-coursecast-41ma</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjow5y2dt3aogdr4jrli.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvjow5y2dt3aogdr4jrli.png" alt="CourseCast Dashboard Home" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the story of how I made a Monte Carlo simulation of student schedule assignments &lt;strong&gt;600x faster&lt;/strong&gt; with web workers.&lt;/p&gt;

&lt;p&gt;Here is our baseline: the original prototype struggled to handle ~100 concurrent users. Each simulation request to the compute server took a whole minute (~60 seconds) to complete, which incidentally exasperated the resource limits of the deployment.&lt;/p&gt;

&lt;p&gt;In this article, we'll discuss the steps that I took to make the application virtually infinitely scalable (i.e., no server compute bottleneck) thanks to sub-second client-side execution. &lt;em&gt;That's faster than a page load!&lt;/em&gt; 🔥&lt;/p&gt;

&lt;h2&gt;
  
  
  Simulating Course Match with CourseCast
&lt;/h2&gt;

&lt;p&gt;CourseCast is a course schedule simulator by &lt;a href="https://www.linkedin.com/in/derekjgibbs/" rel="noopener noreferrer"&gt;Derek Gibbs&lt;/a&gt; for the &lt;a href="https://mba-inside.wharton.upenn.edu/course-match/" rel="noopener noreferrer"&gt;Course Match&lt;/a&gt; system of the &lt;a href="https://www.wharton.upenn.edu/" rel="noopener noreferrer"&gt;Wharton School&lt;/a&gt; of the &lt;a href="https://www.upenn.edu/" rel="noopener noreferrer"&gt;University of Pennsylvania&lt;/a&gt;. In the actual Course Match system, each student rates desired courses on a scale from 0 (least desired) to 100 (most desired). This score is known as the &lt;strong&gt;"course utility"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On simulation day, the Course Match algorithm determines the &lt;strong&gt;"clearing price"&lt;/strong&gt; for all offered courses based on their supply and demand. Upon completion, Course Match will have been able to assign schedules to each student (in a single round!) such that the course utilities and obtained credits are maximized given the student's respective budget constraints.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 You can think of Course Match as an autonomous shopper that "buys" courses on behalf of the student. The purchasing power is only limited by the student's token budget, their maximum workload/credits, and their assigned utilities. The higher the token budget, the greater the student's capability to "afford" the clearing price for a course.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3awy0jfp5g3y7ozkj66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3awy0jfp5g3y7ozkj66.png" alt="CourseCast Course Utility Configuration" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since it's impossible to know ahead of time what the actual clearing prices will be, CourseCast instead forecasts the clearing prices based on the most recent historical data of actual clearing prices in previous Course Match runs. These predicted prices (and their statistical variances) are the "weights" of the model trained on the latest course and instructor trends.&lt;/p&gt;

&lt;p&gt;To account for forecast uncertainty, the CourseCast model assumes that the predicted clearing price is a normally distributed random variable. As such, CourseCast runs 100 Monte Carlo simulations and counts the frequency of particular courses and schedule configurations being selected. These simulation results are presented to the user as a probability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxcq51t9gy8lkkqnl9uq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxcq51t9gy8lkkqnl9uq.png" alt="CourseCast Simulation Results" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So where was the bottleneck?
&lt;/h2&gt;

&lt;p&gt;The original CourseCast 2024 was prototyped and deployed as a &lt;a href="https://streamlit.io/" rel="noopener noreferrer"&gt;Streamlit&lt;/a&gt; application written in Python. Students would input their course utilities and submit their simulation request to the Streamlit Community Cloud where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Python back end on &lt;em&gt;shared virtual compute resources&lt;/em&gt; would parse course data and load model weights from a hosted Excel spreadsheet.&lt;/li&gt;
&lt;li&gt;The service would recompute all of the scheduling conflicts between courses (~200 in total). Example: classes with overlapping schedules, classes with overlapping sections, and other logistical constraints.&lt;/li&gt;
&lt;li&gt;Run 100 Monte Carlo simulations &lt;em&gt;sequentially&lt;/em&gt;. Each of which is an instance of a linear programming solver.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As CourseCast went viral among thousands of UPenn students, the scalability cracks began to show. When too many concurrent users hammered the Streamlit application, students couldn't run their simulations.&lt;/p&gt;

&lt;p&gt;To be fair, the application was on the Streamlit free tier, but it was definitely high time for a rewrite to something more production-grade.&lt;/p&gt;

&lt;h2&gt;
  
  
  So how did we scale CourseCast 2025?
&lt;/h2&gt;

&lt;p&gt;Now that we know where the bottlenecks are, let's tackle them one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scrapping the Python Server
&lt;/h3&gt;

&lt;p&gt;My first instinct was to ask: &lt;em&gt;is Python necessary at all?&lt;/em&gt; The Monte Carlo simulation was essentially a glorified &lt;code&gt;for&lt;/code&gt; loop over a linear programming solver. Nothing about the core simulation logic was specific to Python. In fact, the only Python-specific implementation detail was the usage of Excel spreadsheet parser libraries and linear programming solver libraries for Python. I figured...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there was a way to package and compress the Excel spreadsheet in a web-friendly format, then there's nothing stopping us from loading the entire dataset in the browser!&lt;sup id="fnref1"&gt;1&lt;/sup&gt; Sure enough, the &lt;a href="https://parquet.apache.org/" rel="noopener noreferrer"&gt;Parquet&lt;/a&gt; file format was specifically designed for efficient portability.&lt;/li&gt;
&lt;li&gt;If there was an equivalent linear programming solver library in JavaScript, then there's nothing stopping us from running simulations in the browser! Sure enough, there was the &lt;a href="https://www.npmjs.com/package/yalps" rel="noopener noreferrer"&gt;&lt;code&gt;yalps&lt;/code&gt;&lt;/a&gt; library (among many other options).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, I was fully convinced that we could scrap the Python server and compute the simulation entirely in the browser. This approach effectively allows us to infinitely scale our simulation capacity as we would no longer be constrained by shared cloud compute limits.&lt;/p&gt;

&lt;p&gt;That solves our scalability problem! ✅&lt;/p&gt;

&lt;h3&gt;
  
  
  Precomputing Static Course Conflicts
&lt;/h3&gt;

&lt;p&gt;The next bottleneck was the course conflict generation logic. Recall that &lt;em&gt;each&lt;/em&gt; simulation request recomputes the logistical constraints on course selections (e.g., disallowing classes with overlapping schedules). This is fairly non-trivial work as there are hundreds of classes to consider.&lt;/p&gt;

&lt;p&gt;So, naturally, the solution is to precompute these conflicts ahead of time. The precompute script takes the raw course data and appends the "conflict groups" of each course. These "conflict groups" ultimately determine the statically known logistical constraints of the linear programming solver.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 In computer science parlance, you can think of these "conflict groups" as equivalence classes defined by the relation of overlapping course schedules. That is to say, for all pairs of courses within an equivalence class, their schedules must have a non-empty schedule intersection. Thus, a "conflict group" is just a label for a group of pairwise-intersecting courses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All of the course metadata, seeded random values, and conflict groups are embedded in a single compressed &lt;code&gt;courses.parquet&lt;/code&gt; file (~90 KiB) and served to the user via a CDN for efficient delivery and caching. There is also the option of caching the file in a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" rel="noopener noreferrer"&gt;Service Worker&lt;/a&gt;, but the edge CDN already works well enough.&lt;/p&gt;

&lt;p&gt;That solves our repeated work problem! ✅&lt;/p&gt;

&lt;h3&gt;
  
  
  Offloading CPU-Bound Work to a Separate Thread
&lt;/h3&gt;

&lt;p&gt;The next bottleneck is the sequential execution of Monte Carlo simulation runs. There's actually no reason for us to run them sequentially because each sampled price prediction is independent from the 99 other trials. The simulation can thus be parallelized at the trial level.&lt;/p&gt;

&lt;p&gt;Since each simulation run is primarily a linear programming solver, we know that the work is CPU-bound, not I/O-bound. The &lt;code&gt;async&lt;/code&gt;-&lt;code&gt;await&lt;/code&gt; model will &lt;strong&gt;not&lt;/strong&gt; work here because &lt;a href="https://dev.to/somedood/javascript-concurrency-avoiding-the-sequential-trap-7f0"&gt;CPU-bound work blocks the event loop&lt;/a&gt;. We &lt;strong&gt;must&lt;/strong&gt; offload the work to another thread to keep the UI responsive.&lt;/p&gt;

&lt;p&gt;In the browser, we only have one way to spawn multiple threads: through the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API" rel="noopener noreferrer"&gt;Web Worker API&lt;/a&gt;.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The API is a little wonky in that it accepts a URL to a script.&lt;/span&gt;
&lt;span class="c1"&gt;// This will be the entry point of the web worker.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Modern bundlers support URL imports. Prefer this approach!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="c1"&gt;// NOTE: the import path is relative!&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./worker.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then wrap the worker message-passing logic in a &lt;code&gt;Promise&lt;/code&gt; interface and leverage libraries like &lt;a href="https://tanstack.com/query/latest" rel="noopener noreferrer"&gt;TanStack Query&lt;/a&gt; for clean pending states in the UI. The example below uses React for demonstration, but this pattern is framework-agnostic.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// hooks.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@tanstack/react-query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WorkRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Alternatively: receive this as an argument.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AbortController&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;withResolvers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Set up event listeners that clean up after themselves&lt;/span&gt;
  &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signal&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Kick off the work once all listeners are hooked up&lt;/span&gt;
  &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Parse the incoming data with Zod or Valibot for type safety!&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;WorkResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Make sure we don't leave any dangling workers!&lt;/span&gt;
    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Useful for sending work on mount! */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useSendWorkQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;WorkRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;worker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c1"&gt;// Ensure that data is always fresh until revalidated.&lt;/span&gt;
    &lt;span class="na"&gt;staleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;static&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Ensure simulations rerun immediately upon invalidation.&lt;/span&gt;
    &lt;span class="na"&gt;gcTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// worker.ts&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Parse with Zod for runtime safety!&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;RequestSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Do heavy CPU-bound work here&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResponseSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doHeavyWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Pass the results back to the UI&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;once&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// assumes one-shot requests&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That solves our responsive UI problem! ✅&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallelizing with Worker Thread Pools
&lt;/h3&gt;

&lt;p&gt;A more advanced implementation of this one-shot request-response worker architecture leverages thread pools to send work to already initialized workers (as opposed to re-initializing them for each work request).&lt;/p&gt;

&lt;p&gt;We can use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency" rel="noopener noreferrer"&gt;&lt;code&gt;navigator.hardwareConcurrency&lt;/code&gt;&lt;/a&gt; to determine the optimal number of worker threads to spawn in the pool. Spawning more workers than the maximum hardware concurrency is pointless because the hardware would not have enough cores to service that parallelism anyway.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ In the previous section, the &lt;code&gt;worker&lt;/code&gt; was initialized by the &lt;code&gt;sendWork&lt;/code&gt; function. In a worker pool, this should instead be provided as an argument to the &lt;code&gt;sendWork&lt;/code&gt; function because &lt;code&gt;sendWork&lt;/code&gt; is no longer the "owner" of the thread resource and thus has no say in the worker lifetime. Worker termination &lt;strong&gt;must&lt;/strong&gt; be the responsibility of the thread pool, not the sendWork function.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// hooks.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;chunked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ranged&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zip&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;itertools&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@tanstack/react-query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doWorkInThreadPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RequestSchema&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Yes, this is the thread pool...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hardwareConcurrency&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./worker.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`worker-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Distribute the work in a round-robin fashion&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponseSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jobs&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;chunked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sendWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Clean up the thread pool when we're done!&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/** Execute a batch of work on mount! */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useThreadPoolWorkQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RequestSchema&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pool&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;queryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;doWorkInThreadPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;staleTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;static&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;gcTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📝 Request cancellation is not implemented here for the sake of brevity, but it is fairly trivial to forward the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal" rel="noopener noreferrer"&gt;&lt;code&gt;AbortSignal&lt;/code&gt;&lt;/a&gt; from TanStack Query into the thread pool. It's only a matter of terminating the workers upon receiving the &lt;code&gt;abort&lt;/code&gt; event.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The thread pool optimization allowed us to run 100 simulations in parallel batches across all of the device's cores. Together with the precomputed conflict groups, the Monte Carlo simulation was effectively reduced from a minute to sub-second territory! 🔥&lt;/p&gt;

&lt;p&gt;That solves our performance problems! ✅&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;After all of these optimizations, I upgraded CourseCast from a prototype that struggled with a hundred concurrent users (with ~60 seconds per simulation request) to an infinitely scalable simulator with sub-second execution speeds (faster than a page load!).&lt;/p&gt;

&lt;p&gt;CourseCast now guides 1000+ UPenn students to make informed decisions and (blazingly!) fast experiments about their course schedules. And we're just getting started! 🚀&lt;/p&gt;

&lt;p&gt;Throughout this work, I had a few key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always leave the door open for the possibility of offloading compute to the browser. Modern Web APIs are highly capable with great browser support nowadays. Keep exploring ways to save ourselves from the infrastructure burden of bespoke Python services.&lt;/li&gt;
&lt;li&gt;Always find opportunities to precompute static data. May it be through a precompute script like in CourseCast or a materialized view in the database, strive to do the least amount of repeated work.&lt;/li&gt;
&lt;li&gt;Keep a sharp eye out for parallelizable work. There are many opportunities in data science and general scientific computing where data processing need not be sequential (e.g., dot products, seeded simulation runs, independent events, etc.).&lt;/li&gt;
&lt;li&gt;Be extra mindful of the distinction between &lt;a href="https://dev.to/somedood/javascript-concurrency-avoiding-the-sequential-trap-7f0"&gt;CPU-bound work and I/O-bound work&lt;/a&gt; when interfacing with lengthy operations in the user interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a more human perspective, it's always a pleasure to have the code that I write be in service of others—especially students! As software engineers, it's easy to forget about the human users at the other end of the screen. To be reminded of the positive impact of our code on others never fails to make our work all the more worth it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Have been hearing tons of amazing feedback. Anecdotally, most people who ran simulations through CourseCast ended up without any surprises. Congrats on shipping a great product!"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;Thanks to &lt;a href="https://www.linkedin.com/in/derekjgibbs/" rel="noopener noreferrer"&gt;Derek Gibbs&lt;/a&gt; and the &lt;a href="https://casperstudios.xyz/" rel="noopener noreferrer"&gt;Casper Studios&lt;/a&gt; team for trusting me to take the lead on this project! And thanks to the Wharton School administration for their support and collaboration with us in making CourseCast as helpful as it can be for the students.&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;I must disclaim that our dataset is public and fairly small. For larger models with possibly proprietary weights, downloading the data in the browser is not an option. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>You're slicing your architecture wrong!</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Thu, 15 May 2025 13:29:45 +0000</pubDate>
      <link>https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9</link>
      <guid>https://dev.to/somedood/youre-slicing-your-architecture-wrong-4ob9</guid>
      <description>&lt;p&gt;For the longest time, the &lt;strong&gt;"separation of concerns"&lt;/strong&gt; has been the ultimate guiding principle of software engineering. We thus structure our codebases accordingly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grouping related files by responsibility;&lt;/li&gt;
&lt;li&gt;Partitioning logic by technical layers;&lt;/li&gt;
&lt;li&gt;And sometimes even isolating by programming language.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Popular architectural patterns such as the &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" rel="noopener noreferrer"&gt;Model-View-Controller (MVC)&lt;/a&gt; have applied and codified this principle to the point of dogma. Universities, bootcamps, and courses &lt;em&gt;everywhere&lt;/em&gt; teach and perpetuate the notion that the MVC architecture is the be-all and end-all of architectural patterns.&lt;/p&gt;

&lt;p&gt;To be fair, the MVC architecture is indeed often the correct mental model for fathoming any &lt;a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete" rel="noopener noreferrer"&gt;CRUD&lt;/a&gt;-heavy application (i.e., virtually 99.9% of web applications&lt;sup id="fnref2"&gt;2&lt;/sup&gt;) because it formalizes the flow of data from the source (i.e., the "model") to the interface (i.e., the "view") as well as the mutation and actuation on said data (i.e., the "controller"). It is quite literally the essence of CRUD.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But, is MVC also the correct framework for structuring codebases?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Does MVC supposedly&lt;sup id="fnref3"&gt;3&lt;/sup&gt; being the correct mental model necessarily mean we should structure our directories as such?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article, we'll explore a &lt;em&gt;better&lt;/em&gt; way to structure a codebase using a &lt;strong&gt;vertically sliced architecture&lt;/strong&gt; instead of the classic &lt;code&gt;models/&lt;/code&gt;, &lt;code&gt;views/&lt;/code&gt;, and &lt;code&gt;controllers/&lt;/code&gt; layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Horizontally Sliced Architectures
&lt;/h2&gt;

&lt;p&gt;The MVC architecture is an example of a &lt;strong&gt;horizontally sliced architecture&lt;/strong&gt;. In a horizontally sliced architecture, the separation of concerns is sliced according to technical layers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjo5ook27d2ab2t3vkx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjo5ook27d2ab2t3vkx1.png" alt="A diagram of a horizontally sliced three-layer architecture featuring the MVC architecture" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that the layers needn't be exclusively "models", "views", and "controllers". In a full-stack web application, you might find yourself slicing by "components", "endpoints", and "databases" instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;models/
├── feature-a.ts
├── feature-b.ts
└── feature-c.ts
controllers/
├── feature-a.ts
├── feature-b.ts
└── feature-c.ts
views/
├── feature-a.tsx
├── feature-b.tsx
└── feature-c.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;So, what's wrong with this project structure?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To add a new feature, you &lt;em&gt;must&lt;/em&gt; jump between multiple directories—namely &lt;code&gt;models/feature/*&lt;/code&gt;, &lt;code&gt;controllers/feature/*&lt;/code&gt;, and &lt;code&gt;views/feature/*&lt;/code&gt;. Compounded over time, that's a &lt;em&gt;lot&lt;/em&gt; of context-switching, mental overhead, and navigational ceremony!&lt;/li&gt;
&lt;li&gt;It's often not immediately apparent which modules are used by a particular feature. As everything is horizontally sliced, each module can theoretically import &lt;em&gt;any&lt;/em&gt; module from the layer below. This makes it difficult to track and assess the impact of code changes.&lt;/li&gt;
&lt;li&gt;Consequently, modules across layers within the scope of a single feature tend to exhibit high coupling and low-to-medium cohesion.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"Uh... which files go where again?"&lt;/em&gt; – Probably you for the past 10 minutes, thinking about where to put new files for a feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Vertically Sliced Architectures
&lt;/h2&gt;

&lt;p&gt;Now let's turn MVC on its side—literally! In a &lt;strong&gt;vertically sliced architecture&lt;/strong&gt;, the separation of concerns is sliced according to features. The core idea being: each feature module must encapsulate only its own &lt;em&gt;end-to-end&lt;/em&gt; logic and nothing else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pscpfruj09x09hwbdz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2pscpfruj09x09hwbdz7.png" alt="A diagram of a vertically sliced three-layer architecture where a feature module is superimposed on all layers of the tech stack" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In practice, here is what a feature-driven project structure could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;features/
├── feature-a/
│   ├── model.ts
│   ├── controller.ts
│   └── view.tsx
├── feature-b/
│   ├── model.ts
│   ├── controller.ts
│   └── view.tsx
└── feature-c/
    ├── model.ts
    ├── controller.ts
    └── view.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shared logic across multiple features (e.g., database models, common utilities, etc.) may of course be refactored into shared modules elsewhere. What's important is that the feature-specific logic is &lt;em&gt;self-contained&lt;/em&gt; and &lt;em&gt;end-to-end&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Interestingly, though, the MVC patterns have not totally disappeared even in a vertically sliced architecture—as evidenced by the internal &lt;code&gt;model.ts&lt;/code&gt;, &lt;code&gt;controller.ts&lt;/code&gt;, and &lt;code&gt;view.tsx&lt;/code&gt; files &lt;em&gt;within&lt;/em&gt; a particular feature module. The slicing is different, yet the MVC-style separation of concerns remains in spirit.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So, what makes this better?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All the code related to a particular feature can be found within a single directory. No more back-and-forth between distant directories!&lt;sup id="fnref4"&gt;4&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;The collocation of end-to-end logic lessens the cognitive load when developing features or debugging behaviors.&lt;sup id="fnref5"&gt;5&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;By construction, a feature-driven architecture naturally leads to highly independent feature modules that exhibit low coupling (&lt;em&gt;between&lt;/em&gt; vertical slices) and high cohesion (&lt;em&gt;within&lt;/em&gt; vertical slices).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example: React + Next.js
&lt;/h2&gt;

&lt;p&gt;Nowadays, most full-stack web frameworks provide routing as a first-class feature. In Next.js, the &lt;code&gt;src/app/&lt;/code&gt; directory contains the entry points for each route. Specifically, the &lt;code&gt;page.tsx&lt;/code&gt; file exports the component that should be rendered onto the page for that particular route.&lt;/p&gt;

&lt;p&gt;Now let's imagine the &lt;code&gt;page.tsx&lt;/code&gt; file as an orchestrator that only imports feature modules from &lt;code&gt;src/features/&lt;/code&gt;. A natural conclusion is that a vertically sliced project structure entails partitioning the application logic as self-contained "feature components" that can be imported by any route—or any entry point in general.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── app/
│   ├── dashboard/
│   │   ├── layout.tsx
│   │   └── page.tsx
│   └── page.tsx
├── features/
│   ├── create-order/
│   │   ├── index.tsx
│   │   ├── context.ts
│   │   ├── hooks.ts
│   │   └── actions.ts
│   └── login-form/
│       ├── index.tsx
│       ├── context.ts
│       ├── hooks.ts
│       └── actions.ts
├── database/
│   ├── index.ts
│   └── schema.ts
└── components/
    ├── card.tsx
    ├── button.tsx
    └── input.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, feature modules like &lt;code&gt;create-order&lt;/code&gt; and &lt;code&gt;login-form&lt;/code&gt; may contain feature-specific components, contexts, hooks, and server actions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A feature-specific component may, for example, import from the shared &lt;code&gt;src/components/&lt;/code&gt; directory for common cards, buttons, and inputs.&lt;/li&gt;
&lt;li&gt;Meanwhile, a feature-specific server action may invoke database queries from the shared &lt;code&gt;src/database/&lt;/code&gt; directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is to know when to extract shared logic (e.g., &lt;code&gt;src/database/&lt;/code&gt; and &lt;code&gt;src/components/&lt;/code&gt;) and when to keep bespoke feature-specific logic isolated from the rest of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;At its core, the call to action is simple: &lt;em&gt;simply turn MVC on its side.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Vertically sliced architectures set us up to write highly independent components that exhibit low coupling (&lt;em&gt;between&lt;/em&gt; vertical slices) and high cohesion (&lt;em&gt;within&lt;/em&gt; vertical slices). The result is a project structure that is considerably easier to read, understand, maintain, and extend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.jimmybogard.com/vertical-slice-architecture/" rel="noopener noreferrer"&gt;"Vertical Slice Architecture"&lt;/a&gt; by Jimmy Bogard&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Command_Query_Responsibility_Segregation" rel="noopener noreferrer"&gt;"Command Query Responsibility Segregation"&lt;/a&gt; from Wikipedia&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cqrs.wordpress.com/wp-content/uploads/2010/11/cqrs_documents.pdf" rel="noopener noreferrer"&gt;"CQRS Documents"&lt;/a&gt; by Greg Young&lt;/li&gt;
&lt;/ul&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;For example, in web development, it is quite common to have a dedicated &lt;code&gt;css/&lt;/code&gt; directory for stylesheets and a &lt;code&gt;js/&lt;/code&gt; directory for scripts. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Citation needed. 😅 ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;For the sake of this article, we assume this to be generally true: that MVC is &lt;em&gt;indeed&lt;/em&gt; the correct mental model for fathoming CRUD-heavy applications. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Admittedly, back-and-forth between sub-directories is nevertheless inevitable. However, the navigation is at least contained within a single core directory now instead of jumping between distant directories, which is a win in my book. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;I can only back this up with my own personal experience as well as anecdotal evidence from my friends. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>beginners</category>
      <category>architecture</category>
      <category>webdev</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Beware the Global Const</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Sat, 19 Apr 2025 08:33:23 +0000</pubDate>
      <link>https://dev.to/somedood/beware-the-global-const-3cf7</link>
      <guid>https://dev.to/somedood/beware-the-global-const-3cf7</guid>
      <description>&lt;p&gt;It is common wisdom in the programming world to discourage the use of global variables.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is bug-prone due to shared mutability across modules.&lt;/li&gt;
&lt;li&gt;It introduces implicit dependencies within interfaces that are not syntactically communicated.&lt;/li&gt;
&lt;li&gt;It may alter the behavior of dependents across invocations—even when provided with the same arguments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've recently come across a bug that humbled and reminded me about these pitfalls. Let me tell you a cautionary tale about global configuration objects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER:&lt;/strong&gt; The following story is &lt;em&gt;based&lt;/em&gt; on an actual bug in one of the projects that I work on, but several details have been altered and simplified.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A race condition?
&lt;/h2&gt;

&lt;p&gt;The bug was initially simple. A user reported that generating a profile page in the app with ✨AI✨ in quick succession resulted in some components in the page persisting the old values from the previous ✨AI✨ generation.&lt;/p&gt;

&lt;p&gt;"Simple," I naively thought to myself, "It's a classic case of a race condition." I hypothesized that the previous generation completed &lt;em&gt;after&lt;/em&gt; the current one, which resulted in the old values overwriting the new ones in the database. The only problem was: I couldn't find the race condition.&lt;/p&gt;

&lt;p&gt;Each ✨AI✨ enrichment is persisted as a single row in the database. Even if a race condition were to happen, the generated profile page should swap out the contents on a per-generation basis (i.e., one row as a whole). This was clearly not the case as the generated page interleaved new and old contents.&lt;/p&gt;

&lt;p&gt;Sure enough, the database was intact. Each ✨AI✨ enrichment was indeed isolated from each other. No interleaving fields. No missing properties. No bad data. Nothing suspicious at all...&lt;/p&gt;

&lt;h2&gt;
  
  
  It's a front-end bug, then?
&lt;/h2&gt;

&lt;p&gt;"Okay, surely the bug is in the front end," I thought to myself. I looked into the root component that renders the profile page starting with the props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// A vastly simplified recreation of the page.&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// From the database...&lt;/span&gt;
    &lt;span class="nl"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProfileDetails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HeroBanner&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bannerUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing seemed off as the page component was literally just rendering what was given to it. "The bug must be in the data loading," I deduced. After some &lt;code&gt;console.log&lt;/code&gt; debugging, I confirmed that the rows from the database were still intact. At this point, I was fairly confident that the persisted data was not at fault.&lt;/p&gt;

&lt;p&gt;Despite my best efforts, I could not reproduce the bug. The data loaded from an enrichment row exactly matched the details rendered in the page. I mean... that's why race conditions are so difficult to debug, huh? At this point, I could only rely on my detective skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  The dangers of default configurations
&lt;/h2&gt;

&lt;p&gt;A couple hours passed when I finally raised my eyebrow at the call site of the &lt;code&gt;Profile&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @/profile&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_PROFILE_DETAILS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bannerUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash.merge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_PROFILE_DETAILS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getProfileDetails&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/db&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getSessionAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSessionAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profileDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getProfileDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_PROFILE_DETAILS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;profileDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Profile&lt;/span&gt; &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait a minute. Zoom in... &lt;em&gt;Enhance!&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_PROFILE_DETAILS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;profileDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 💥&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there it was: the single line of code that cost me several hours of my life.&lt;/p&gt;

&lt;p&gt;Let me fill you in with the details. The &lt;code&gt;merge&lt;/code&gt; utility here is Lodash's &lt;a href="https://lodash.com/docs/4.17.15#merge" rel="noopener noreferrer"&gt;&lt;code&gt;_.merge&lt;/code&gt;&lt;/a&gt;. As its name suggests, &lt;code&gt;merge&lt;/code&gt; recursively merges one object with another. The key word is "recursive"; we can't use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax" rel="noopener noreferrer"&gt;spread syntax&lt;/a&gt; because that will only do a shallow merge.&lt;/p&gt;

&lt;p&gt;Now, we want to merge the database-enriched &lt;code&gt;profileDetails&lt;/code&gt; into the &lt;code&gt;DEFAULT_PROFILE_DETAILS&lt;/code&gt;. This is because the ✨AI✨ prompt may possibly fail for some fields, so we need fallback values when that happens. Here is where the issue arises:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From the &lt;a href="https://lodash.com/docs/4.17.15#merge" rel="noopener noreferrer"&gt;Lodash documentation&lt;/a&gt;: &lt;em&gt;"this method mutates the &lt;code&gt;object&lt;/code&gt;."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because of this, it was totally possible (and documented!) that profile-specific details could &lt;em&gt;leak&lt;/em&gt; into the &lt;code&gt;DEFAULT_PROFILE_DETAILS&lt;/code&gt;—thereby causing subsequent requests to read leaked values. 😱 Suddenly, this innocent bug escalated into a data privacy issue!&lt;/p&gt;

&lt;h2&gt;
  
  
  Aside on serverless environments
&lt;/h2&gt;

&lt;p&gt;This still begs the question: &lt;em&gt;why hasn't the bug come up regularly enough for anyone to notice for a long time?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One important thing to note is that the app is deployed in a serverless environment. That means function invocations are typically ephemeral. JavaScript objects that are created within a request only exist within the lifetime of that request. By design, subsequent requests spin up new instances (a.k.a. isolates) of the environment.&lt;/p&gt;

&lt;p&gt;On paper, the &lt;code&gt;DEFAULT_PROFILE_DETAILS&lt;/code&gt; should be reconstructed for each request, which sidesteps the entire issue. However, cloud hosting providers can do clever performance optimizations like preserving the isolate across multiple requests to eliminate cold boot times.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This is why the bug only manifests itself in "quick succession". There's a small non-deterministic window of opportunity where rendering a profile leaks details from a previous request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some mitigations and workarounds
&lt;/h2&gt;

&lt;p&gt;The knee-jerk reaction is to axe the &lt;code&gt;_.merge&lt;/code&gt; utility. But to be fair, there are several mitigations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Merging into a newly constructed object...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_PROFILE_DETAILS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;profileDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Merging into a newly cloned object...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_PROFILE_DETAILS&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;profileDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Refactoring to use factory functions...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createDefaultProfileDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createDefaultProfileDetails&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;profileDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ASIDE:&lt;/strong&gt; using &lt;code&gt;Object.freeze&lt;/code&gt; doesn't really solve the issue because it prevents the mutation of the object during the merge process (which is a behavioral regression!). Also, TypeScript would not save us from the bug anyway even if it were annotated as &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype" rel="noopener noreferrer"&gt;&lt;code&gt;Readonly&lt;/code&gt;&lt;/a&gt; due to the way &lt;code&gt;_.merge&lt;/code&gt; is &lt;a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a2293665c880f8b59794bca227db53c8a84c4a7f/types/lodash/common/object.d.ts#L1838" rel="noopener noreferrer"&gt;typed&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The common thread in all of these mitigations is avoiding mutation in global configuration objects. In the end, I committed to replacing all instances of non-primitive global &lt;code&gt;const&lt;/code&gt; exports throughout the codebase into factory functions. In fact, banning non-primitive exports altogether was a safe bet.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Lesson learned: avoid non-primitive (e.g., objects, classes, maps, sets, regular expressions, functions, etc.) global exports if you can.&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Not to be confused with "global constants", by the way. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;This is a good thing, by the way! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>architecture</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>The Curse of Verbosity and Indirection</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Sun, 23 Mar 2025 17:23:24 +0000</pubDate>
      <link>https://dev.to/somedood/the-curse-of-verbosity-and-indirection-1a95</link>
      <guid>https://dev.to/somedood/the-curse-of-verbosity-and-indirection-1a95</guid>
      <description>&lt;p&gt;I've dealt with a wide spectrum of programming languages over the years. Some languages are object-oriented (e.g., Java, PHP, C++, and Dart); some are procedural (e.g., C and Zig); some are functional (e.g., Haskell, Coq); some are declarative (e.g., HTML and CSS); some are a mixed bag of everything (e.g., JavaScript, Python, Rust); and some are straight-up machine code (e.g., x86, ARM, MIPS, and RISC-V).&lt;/p&gt;

&lt;p&gt;One common theme that I've observed is that object-oriented programming (OOP) patterns tend to yield the most verbose and indirect abstractions versus their non-OOP counterparts. In this article, we'll investigate why this is the case and how it arises out of necessity.&lt;/p&gt;

&lt;h1&gt;
  
  
  Free functions as a first-class citizen
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.hello&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello world!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello world!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's compare two "hello world" programs: one from Java and another from Rust. It wouldn't be controversial to assert that the Rust version is clearly more concise than the Java version. To be fair, there is a lot more magic abstracted away: the command-line arguments being the most notable omission.&lt;/p&gt;

&lt;p&gt;Putting that aside, this example illustrates the key limitation of "pure" OOP that makes it so verbose: &lt;em&gt;classes are the only first-class citizens at the top level.&lt;/em&gt; Functions, on the other hand, are second-class citizens that must belong to either a class (as a &lt;code&gt;static&lt;/code&gt; method) or an object (as an instance method).&lt;/p&gt;

&lt;p&gt;When classes are imposed as the top-level entity, class declaration boilerplate becomes a &lt;em&gt;necessary&lt;/em&gt; syntactic and semantic overhead. Instead of defining the entry point as a free function (as one typically would at the assembly level), a strictly OOP language introduces a class indirection right from the start.&lt;/p&gt;

&lt;p&gt;The Zig language—at least &lt;a href="https://ziglang.org/documentation/0.14.0/#import" rel="noopener noreferrer"&gt;as of writing&lt;/a&gt;—brilliantly compromises on that mental model by treating files as implicit &lt;code&gt;struct&lt;/code&gt;s. Top-level items in a file would be as if everything had been wrapped by an invisible &lt;code&gt;struct { ... }&lt;/code&gt; declaration.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="c"&gt;// example.zig&lt;/span&gt;
&lt;span class="c"&gt;// struct {&lt;/span&gt;

&lt;span class="c"&gt;// Not exported...&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;// Exported as a static method!&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"world"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="c"&gt;// main.zig&lt;/span&gt;
&lt;span class="c"&gt;// struct {&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./example.zig"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Static method!&lt;/span&gt;
    &lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c"&gt;// world&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interestingly, this is somewhat equivalent to the Java module system. The only difference is that the &lt;code&gt;class&lt;/code&gt; boilerplate is implied, which makes things a little bit more bearable (as far as "hello world" examples go).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 A cute consequence of the Zig module system is that a file can also define &lt;code&gt;struct&lt;/code&gt; instance fields at the top level!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Closures as a first-class citizen
&lt;/h1&gt;

&lt;p&gt;Let's talk about "design patterns". In the software engineering world, design patterns—although generic by name—are most colloquially associated with OOP languages. Design patterns impose common terminology and implementation details in an effort to wrangle and make sense of a sea of OOP abstractions.&lt;/p&gt;

&lt;p&gt;How did we get here? How did we end up with an entire vocabulary of jargon&lt;sup id="fnref1"&gt;1&lt;/sup&gt; just to fathom the levels of indirection? And most importantly, are these &lt;em&gt;necessary&lt;/em&gt; and relevant today?&lt;/p&gt;

&lt;p&gt;Let's first put into context that a lot of these design patterns were popularized and mainstreamed by a computer science zeitgeist constrained by the hardware and compiler capabilities of its time.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;class&lt;/code&gt; as a language feature was a &lt;em&gt;necessarily&lt;/em&gt; limited compiler abstraction. Anything more complex than the core offering of fields, methods, and inheritance was an incredible feat of static analysis.&lt;sup id="fnref2"&gt;2&lt;/sup&gt; The &lt;code&gt;class&lt;/code&gt; being a simple primitive enabled more arbitrarily complex software, but at the same time also necessitated more abstractions.&lt;/p&gt;

&lt;p&gt;One such nicety of modern hardware and compiler theory that we now take for granted are &lt;strong&gt;closures&lt;/strong&gt; (a.k.a. &lt;strong&gt;lambda functions&lt;/strong&gt;). A closure is any callable (i.e., function-like) object with pre-bound arguments (i.e., doesn't need to be explicitly passed in).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outsideVariable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;closure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// `outsideVariable` is "captured" by the closure.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;outsideVariable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// No need to pass `outsideVariable` as an argument&lt;/span&gt;
&lt;span class="c1"&gt;// because the `closure` had already "pre-bound" it.&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 300&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a closer look at how all of this works. At its core, a closure simply needs to stash some "outside variables" beforehand and provide some way to invoke it later. Kinda like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Closure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;outsideVariable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outsideVariable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;outsideVariable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;outsideVariable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;outsideVariable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;outsideVariable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;closure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Closure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outsideVariable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Poof! 💥 And just like that, we have reinvented the &lt;strong&gt;Strategy Pattern&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The point is: a lot of the verbosity of OOP design patterns come from the fact that (at the time!) there hadn't been language-level primitives for expressing closures. With limited compiler capabilities, the best way to emulate pre-bound functions was via strategy classes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Fortunately, modern Java has had closures since 2014 when Java 8 first released! The C++ folks also got theirs a few years earlier with C++11.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is actually a recurring theme among previously "pure" OOP languages: many &lt;code&gt;class&lt;/code&gt;-based design patterns are obsoleted by the introduction of closures.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strategy? Write a lambda function that adheres to the same contract.&lt;/li&gt;
&lt;li&gt;Factory? Write a lambda function with zero arguments that internally captures the necessary context.&lt;/li&gt;
&lt;li&gt;Observers? Write a lambda function.&lt;/li&gt;
&lt;li&gt;Adapters? Write a mapper lambda function.&lt;/li&gt;
&lt;li&gt;And so on... (I think you get the point!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So to answer the question more directly: yes, the verbosity of OOP design patterns and the opacity of its abstractions &lt;em&gt;were&lt;/em&gt; necessary at the time. Nowadays, not so much. The point is: a lot of the OOP noise and boilerplate can be replaced by the niceties of modern language constructs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Import-once modules as a first-class citizen
&lt;/h1&gt;

&lt;p&gt;Speaking of design patterns, let's talk about singletons. Here is a classic textbook example of an eagerly initialized singleton class in Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.singleton&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Some private state that the singleton relies on...&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Private just to make sure that nobody invokes it&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// NOTE: A public field also works, but having an explicit&lt;/span&gt;
    &lt;span class="c1"&gt;// getter function ensures that callers cannot reassign the&lt;/span&gt;
    &lt;span class="c1"&gt;// internal instance in any way.&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;em&gt;that&lt;/em&gt; is a lot of syntactic ceremony just for a single instance. We can simplify this by a little bit using the &lt;code&gt;final&lt;/code&gt; keyword.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.singleton&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// This is now a `public` but `final` field.&lt;/span&gt;
    &lt;span class="c1"&gt;// It's functionally equivalent to the example&lt;/span&gt;
    &lt;span class="c1"&gt;// above as we only care about ensuring that the&lt;/span&gt;
    &lt;span class="c1"&gt;// internal instance never gets reassigned.&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt; &lt;span class="no"&gt;INSTANCE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;Singleton&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But even then, it's still a bit too verbose. We can go further by removing the constructor and the instantiation entirely. Instead, let's just inline the instance fields as &lt;code&gt;static&lt;/code&gt; fields!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.singleton&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// No longer `final` as this can be modified internally.&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Now `static` because an instance is no longer required.&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;em&gt;this&lt;/em&gt; is much better! Here, the one true "instance" of the class is no "instance" at all; it is &lt;code&gt;static&lt;/code&gt;. There's no need to jump through hoops with constructors, getters, and setters. Classic OOP patterns are so engrossed in classes that we sometimes forget that we don't have to over-complicate things.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Of course, this contrived example doesn't apply if an actual object instance was required by some external library or API. In that case, we can either (1) write a trivial wrapper or (2) revert to the instance-based pattern.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This can be made even simpler if we step out of the "pure" OOP world, where classes are the only first-class top-level language items. If we allow variables and free functions into the top level (i.e., without requiring a &lt;code&gt;class&lt;/code&gt; container), we get at the heart of what we're trying to express.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Not exported to keep it private.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 This example works in JavaScript because the ECMAScript module system requires that imported modules are loaded and evaluated only once.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Unions as a first-class citizen
&lt;/h1&gt;

&lt;p&gt;Another example of a modern language construct is the union or enum.&lt;sup id="fnref3"&gt;3&lt;/sup&gt; The lack of first-class unions (e.g., &lt;a href="https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types" rel="noopener noreferrer"&gt;TypeScript unions&lt;/a&gt; and &lt;a href="https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html" rel="noopener noreferrer"&gt;Rust enums&lt;/a&gt;) force OOP design patterns to resort to inheritance-based polymorphism (e.g., &lt;code&gt;abstract class&lt;/code&gt;) for expressing disjoint use cases. This often leads to infamously opaque indirections across scattered subclasses.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// A base class for all possible "input types".&lt;/span&gt;
&lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InputType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TextInputType&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;InputType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TextInputType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegerInputType&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;InputType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;IntegerInputType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BooleanInputType&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;InputType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;BooleanInputType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In a language that supports first-class unions&lt;/span&gt;
&lt;span class="c1"&gt;// (such as TypeScript), we have a much simpler way&lt;/span&gt;
&lt;span class="c1"&gt;// to express the same idea.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;InputType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Even relatively low-level languages like Rust get this right!&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;InputType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The point is: here we see yet another example of "pure" class-first OOP getting in the way of the core idea that's being expressed by the abstraction. The mandatory &lt;code&gt;class&lt;/code&gt; boilerplate is frankly just overhead—&lt;em&gt;necessarily&lt;/em&gt; self-imposed by the purity of class-first language design.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Many "pure" OOP patterns of yesteryear have poor &lt;strong&gt;signal-to-noise ratios&lt;/strong&gt;. That is to say: there is more syntax and conceptual &lt;strong&gt;noise&lt;/strong&gt; than there is engineering &lt;strong&gt;signal&lt;/strong&gt; and clarity.&lt;/p&gt;

&lt;p&gt;The notoriously verbose and opaque formulation boils down to its insistence on the &lt;code&gt;class&lt;/code&gt; being the only top-level language item. This is not for no reason, though! Limited hardware and compiler capabilities during the heyday of the OOP trend necessitated the &lt;code&gt;class&lt;/code&gt; being the building block of everything.&lt;/p&gt;

&lt;p&gt;To manage all of this &lt;strong&gt;accidental complexity&lt;/strong&gt;, OOP design patterns were codified—many of which are obsoleted by introducing not-so-pure OOP language features such as closures. Nevertheless, the (necessary!) codification of these patterns only justified what would otherwise be undesirable qualities in code.&lt;/p&gt;

&lt;p&gt;Of course, this is not to say that OOP has no place in modern software engineering. There are certainly some abstractions where OOP is an appropriate tool in the box.&lt;sup id="fnref4"&gt;4&lt;/sup&gt; At the very least, what I &lt;em&gt;am&lt;/em&gt; saying is that the "pure" OOP of yesteryear is obsoleted by the modern OOP-functional hybrids of today.&lt;/p&gt;

&lt;p&gt;In fact, I've always been a fan of the Java community's recent efforts in embracing functional programming patterns. Stream helpers, lambda functions, free functions, pattern matching, and monadic optional types are stellar examples of an evolving OOP language that recognizes cleaner ways of doing things.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let's strive to write simpler code devoid of verbose abstractions and opaque indirections.&lt;sup id="fnref5"&gt;5&lt;/sup&gt;&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Strategies, factories, builders, adapters, singletons, decorators, facades, etc. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;In the case of C++, it was also an incredible feat of bike-shedding over syntax and capture semantics! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;In the functional programming world, a stricter subset of unions is known as a "sum type", which are basically "tagged unions". ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;Just to cite one common example in my experience, classes are an appropriate abstraction for database drivers, which are often stateful wrappers over live database connections. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;To give some personal context and motivation behind this article, I had recently worked on a Flutter codebase that subscribed to the so-called &lt;a href="https://docs.flutter.dev/app-architecture/guide" rel="noopener noreferrer"&gt;"Clean Code Architecture"&lt;/a&gt;. It was not, in fact, clean code at all; it was riddled with superfluous OOP abstractions and mishandled &lt;code&gt;async&lt;/code&gt; state. Files upon files of abstractions made the codebase difficult to navigate and extend—much to the irony of the &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID principles&lt;/a&gt; that they swear by. This article summarized the general guidelines on the several opportunities for simplification that I encountered along the way. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>java</category>
      <category>oop</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>I was wrong about array methods and generators...</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Mon, 09 Sep 2024 01:17:31 +0000</pubDate>
      <link>https://dev.to/somedood/i-was-wrong-about-array-methods-and-generators-2ig9</link>
      <guid>https://dev.to/somedood/i-was-wrong-about-array-methods-and-generators-2ig9</guid>
      <description>&lt;p&gt;For the longest time, I've always thought that JavaScript generators perform better than chained array methods in terms of execution time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Surely, I thought that the superior memory efficiency of generators (due to lazy computation) implied better overall execution time as well.&lt;/li&gt;
&lt;li&gt;Surely, in terms of time complexity, the single-pass 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n)&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 nature of generators were superior over the 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(kn)O(kn)&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;kn&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 of 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;kk&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 chained array methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the heuristics that I had been taught by computer science point to generators being the undisputed champion. After many years of personal presumption &lt;del&gt;and dogma&lt;/del&gt;, it's finally time to put that to the test—with statistical rigor of course! So strap on your seatbelts as we finally answer the question:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Are generators actually faster than chained array methods?&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Setup
&lt;/h1&gt;

&lt;p&gt;When we chain array methods, we typically perform a &lt;code&gt;filter&lt;/code&gt; first then the &lt;code&gt;map&lt;/code&gt;. The main idea is that it is more efficient to &lt;code&gt;filter&lt;/code&gt; out the bad data first so that we don't have to &lt;code&gt;map&lt;/code&gt; as many values later on. This will be our primary experiment: a basic &lt;code&gt;filter&lt;/code&gt; + &lt;code&gt;map&lt;/code&gt; operation.&lt;/p&gt;

&lt;p&gt;Let's start with generating 32 KiB of random data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generate 32 KiB of "cyptographically strong random values".&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Then save the buffer into a file.&lt;/span&gt;
&lt;span class="c1"&gt;// Deno is just an implementation detail.&lt;/span&gt;
&lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;random.bin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Below is a histogram of the generated bytes. Indeed, we see a fairly uniform distribution of byte values in the &lt;code&gt;random.bin&lt;/code&gt; file. For the sake of reproducibility and independence, we will now use this binary dump for all experiments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F25sxicr0dtd51x9dv287.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F25sxicr0dtd51x9dv287.png" alt="A histogram of the randomly generated bytes in uniform distribution." width="575" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal is to simply prune out all of the bytes greater than &lt;code&gt;127&lt;/code&gt; (roughly half of &lt;code&gt;random.bin&lt;/code&gt;) and then normalize the data so that the remaining bytes are between &lt;code&gt;0.0&lt;/code&gt; and &lt;code&gt;1.0&lt;/code&gt; (inclusive). Let's now discuss the four cases that we will be testing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Case 1: &lt;code&gt;raw-for-loop&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;By presumption, we consider the raw &lt;code&gt;for&lt;/code&gt; loop construction as the baseline. Here, we iterate over all values in &lt;code&gt;nums&lt;/code&gt; and push the mapped value into the &lt;code&gt;output&lt;/code&gt; array.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rawForLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Case 2: &lt;code&gt;for-of-loop&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A slight variation of the &lt;code&gt;raw-for-loop&lt;/code&gt; case is the &lt;code&gt;for-of-loop&lt;/code&gt; case, which instead uses the &lt;code&gt;for...of&lt;/code&gt; loop to iterate over &lt;code&gt;nums&lt;/code&gt;. Everything else remains the same.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;forOfLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Case 3: &lt;code&gt;array-method&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now we enter the territory of functional programming. Here, we implement the same logic as a two-pass &lt;code&gt;filter&lt;/code&gt; + &lt;code&gt;map&lt;/code&gt; chain.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;arrayMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Case 4: &lt;code&gt;generator&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Finally, we implement the equivalent logic with generators.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;_generatorImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;_generatorImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  The Experiment
&lt;/h1&gt;

&lt;p&gt;Before we run the experiments, let's get the hardware specifications out of the way. Note that future work should reproduce this experiment on native Linux systems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OS:&lt;/strong&gt; Windows 22H2 (Build 19045.4842)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CPU:&lt;/strong&gt; Intel® Core™ i7-10750H CPU @ 2.60GHz (12 CPUs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAM:&lt;/strong&gt; 8192 MB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we implement a CLI for running each experiment case. Here is a high-level overview of the harness logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select one of the four implementations: either &lt;code&gt;raw-for-loop&lt;/code&gt;, &lt;code&gt;for-of-loop&lt;/code&gt;, &lt;code&gt;array-method&lt;/code&gt;, or &lt;code&gt;generator&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Reads the &lt;strong&gt;32-KiB&lt;/strong&gt; &lt;code&gt;random.bin&lt;/code&gt; file for the cached random bytes.&lt;/li&gt;
&lt;li&gt;Perform &lt;strong&gt;2048 warm-up iterations&lt;/strong&gt; to allow the just-in-time compiler to optimize the code.&lt;/li&gt;
&lt;li&gt;Finally, run the actual experiment with high-resolution sub-millisecond timing for &lt;strong&gt;16384 iterations&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;When the standard output is piped into a file, the result is &lt;strong&gt;16384 lines of timing data&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll spare you the gory details of the harness implementation. For those who are interested in the argument parser, the file loader, the implementation selector, and the experiment runner, you may visit the &lt;a href="https://github.com/BastiDood/js-generators-vs-array-methods" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. Please do leave a star while you're there!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/BastiDood" rel="noopener noreferrer"&gt;
        BastiDood
      &lt;/a&gt; / &lt;a href="https://github.com/BastiDood/js-generators-vs-array-methods" rel="noopener noreferrer"&gt;
        js-generators-vs-array-methods
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The repository for all the scripts, notebooks, results, and analyses related to my experiments on JavaScript generators and chained array methods.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;JavaScript Generators vs. Array Methods&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;The repository for all the scripts, notebooks, results, and analyses related to my experiments on JavaScript generators and chained array methods. See the full article &lt;a href="https://dev.to/somedood/i-was-wrong-about-array-methods-and-generators-2ig9" rel="nofollow"&gt;"I was wrong about array methods and generators..."&lt;/a&gt; for more details on the methodology, results, interpretations, and conclusions.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Generating Random Bytes&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;The first step is to generate 32 KiB of random data. There are many ways to do this, but I opted to generate them via the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;Crypto#getRandomValues&lt;/code&gt;&lt;/a&gt; function in JavaScript. A Deno script is already available at &lt;a href="https://github.com/BastiDood/js-generators-vs-array-methodsrandom/random.js" rel="noopener noreferrer"&gt;&lt;code&gt;random/random.js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; This will overwrite the already existing `random.bin` file!&lt;/span&gt;
deno run random/random.js&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Running the Experiments&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Node.js&lt;/span&gt;
&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;run&lt;/span&gt; () { node --experimental-default-type=module benchmark/bench.node.js &lt;span class="pl-smi"&gt;$1&lt;/span&gt; &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; notebook/node/&lt;span class="pl-smi"&gt;$1&lt;/span&gt;.csv&lt;span class="pl-k"&gt;;&lt;/span&gt; }
run raw-for-loop
run for-of-loop
run array-method
run generator&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Deno&lt;/span&gt;
&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;run&lt;/span&gt; () { deno --quiet --allow-read --allow-hrtime benchmark/bench.deno.js -- &lt;span class="pl-smi"&gt;$1&lt;/span&gt; &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; notebook/deno/&lt;span class="pl-smi"&gt;$1&lt;/span&gt;.csv&lt;span class="pl-k"&gt;;&lt;/span&gt; }
run raw-for-loop&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/BastiDood/js-generators-vs-array-methods" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Next, on which runtimes shall we run the experiments? I've selected the three most prominent JavaScript runtimes as of writing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt; (&lt;code&gt;v22.8.0&lt;/code&gt;) is written in C++ and powered by V8.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deno&lt;/strong&gt; (&lt;code&gt;1.46.3&lt;/code&gt;) is written in Rust and powered by V8.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bun&lt;/strong&gt; (&lt;code&gt;1.1.26&lt;/code&gt;) is written in Zig and powered by JavaScriptCore.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The Results
&lt;/h1&gt;

&lt;p&gt;With &lt;strong&gt;2048 warm-up iterations&lt;/strong&gt; and &lt;strong&gt;16384 actual samples&lt;/strong&gt;, I believe it is fair to assume that sample sizes in the experiment are sufficiently large enough to omit the analyses of p-values. After all, with so many samples available, the observed data as a whole is hardly a fluke at that point.&lt;/p&gt;

&lt;p&gt;Instead, the following results and discussion will focus on the pairwise &lt;strong&gt;effect size&lt;/strong&gt; of the sample distributions. Given two sample distributions (e.g., &lt;code&gt;raw-for-loop&lt;/code&gt; versus &lt;code&gt;array-method&lt;/code&gt;), the effect size quantifies how "far apart" the mean of &lt;code&gt;raw-for-loop&lt;/code&gt; is when compared to that of &lt;code&gt;array-method&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, a large negative effect size implies that &lt;code&gt;raw-for-loop&lt;/code&gt; has a significantly lower execution time (good!) than &lt;code&gt;array-method&lt;/code&gt;. In practice, we are effectively quantifying the "impact" of the &lt;code&gt;array-method&lt;/code&gt; on our baseline (i.e., &lt;code&gt;raw-for-loop&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To keep things simple, we will use Cohen's 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;dd&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 as our metric for effect size. As a general rule of thumb, Cohen suggests (but warns against the dogmatization of) the following interpretations for 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;dd&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We say that the effect size is &lt;strong&gt;small&lt;/strong&gt; when 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∣d∣&amp;lt;0.2\left| d \right| &amp;lt; 0.2&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;0.2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/li&gt;
&lt;li&gt;But if 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∣d∣&amp;lt;0.5\left| d \right| &amp;lt; 0.5&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;0.5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, then we consider that to be a &lt;strong&gt;medium&lt;/strong&gt; effect.&lt;/li&gt;
&lt;li&gt;But if 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∣d∣&amp;lt;0.8\left| d \right| &amp;lt; 0.8&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;0.8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, then we have a &lt;strong&gt;large&lt;/strong&gt; effect.&lt;/li&gt;
&lt;li&gt;Otherwise, 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;∣d∣≥0.8\left| d \right| \geq 0.8&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="minner"&gt;&lt;span class="mopen delimcenter"&gt;∣&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mclose delimcenter"&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≥&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;0.8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is a &lt;strong&gt;huge&lt;/strong&gt; effect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we're all on the same page, we can examine the results of the experiment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Node.js Results
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk8jt7jlh68l69oq3q0bd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk8jt7jlh68l69oq3q0bd.png" alt="Histogram of the Node.js Results" width="605" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right off the bat, the Node.js results demolish my long-held presumptions. Not only am I wrong, but it turns out that generators are the slowest of all the cases!&lt;/p&gt;

&lt;p&gt;This histogram still sends shivers down my spine as I recall the countless number of times that I've written generators in my code under the presumption of optimization.&lt;/p&gt;

&lt;p&gt;But how bad is it really? Let's take a look at the numbers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Experiment&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Standard Deviation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;raw-for-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.3309&lt;/td&gt;
&lt;td&gt;0.2828&lt;/td&gt;
&lt;td&gt;0.1975&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for-of-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.3368&lt;/td&gt;
&lt;td&gt;0.2873&lt;/td&gt;
&lt;td&gt;0.2031&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.4360&lt;/td&gt;
&lt;td&gt;0.3557&lt;/td&gt;
&lt;td&gt;0.2404&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.1024&lt;/td&gt;
&lt;td&gt;1.0010&lt;/td&gt;
&lt;td&gt;0.2134&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;By eyeball statistics, we can see right away that the differences between &lt;code&gt;raw-for-loop&lt;/code&gt; (baseline) and &lt;code&gt;for-of-loop&lt;/code&gt; are insignificant. In fact, we can exactly quantify that with Cohen's 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;dd&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. The table below summarizes how the &lt;code&gt;raw-for-loop&lt;/code&gt; compares against the other experiment cases.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;dd&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/th&gt;
&lt;th&gt;&lt;code&gt;raw-for-loop&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for-of-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.0296&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.4778&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-3.7518&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Let's take a look at some key observations here.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Comparing &lt;code&gt;raw-for-loop&lt;/code&gt; and &lt;code&gt;for-of-loop&lt;/code&gt;, we obtain 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈−0.0296d \approx -0.0296&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mord"&gt;0.0296&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. That means &lt;code&gt;raw-for-loop&lt;/code&gt; is only &lt;em&gt;marginally&lt;/em&gt; faster than &lt;code&gt;for-of-loop&lt;/code&gt; up to a &lt;em&gt;very small effect&lt;/em&gt;—so small in fact that it is an injustice to say that there is one!&lt;/li&gt;
&lt;li&gt;We get into the &lt;em&gt;medium&lt;/em&gt; territory between &lt;code&gt;raw-for-loop&lt;/code&gt; and &lt;code&gt;array-method&lt;/code&gt; with 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈−0.4778d \approx -0.4778&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mord"&gt;0.4778&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. That is to say, the &lt;code&gt;raw-for-loop&lt;/code&gt; is faster than the &lt;code&gt;for-of-loop&lt;/code&gt; up to a non-trivial &lt;em&gt;medium effect&lt;/em&gt;. These results are consistent with that by various authors and blog posts over the years.&lt;/li&gt;
&lt;li&gt;Perhaps the most shocking result is the &lt;em&gt;extreme effect&lt;/em&gt; of &lt;code&gt;generator&lt;/code&gt; on &lt;code&gt;raw-for-loop&lt;/code&gt; having 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈−3.7518d \approx -3.7518&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mord"&gt;3.7518&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
! Given these plots, it is fairly conclusive that generators significantly penalize execution time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Going back to the original question, though: &lt;em&gt;how badly do generators compare to chained array methods?&lt;/em&gt; It turns out that the effect size between &lt;code&gt;array-method&lt;/code&gt; and &lt;code&gt;generator&lt;/code&gt; is 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈−2.9315d \approx -2.9315&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mord"&gt;2.9315&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
! Once again, we have entered &lt;em&gt;extreme&lt;/em&gt; territory.&lt;/p&gt;
&lt;h2&gt;
  
  
  Deno Results
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu66yelcfje74hk8ppdk9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu66yelcfje74hk8ppdk9.png" alt="Histogram of the Deno Results" width="605" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hmm... that plot looks eerily familiar. As a matter of fact, we have already seen this plot in the previous section on Node.js!&lt;/p&gt;

&lt;p&gt;Because Node.js and Deno both share V8 as their underlying JavaScript engine, the performance differences between the two are not statistically significant. From this point forward, we can thus refer to Node.js and Deno interchangeably as if they fall under the one umbrella of V8.&lt;/p&gt;

&lt;p&gt;For the sake of completeness, here are the same tables shown in the Node.js section, but in the context of Deno instead.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Experiment&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Standard Deviation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;raw-for-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.3267&lt;/td&gt;
&lt;td&gt;0.2828&lt;/td&gt;
&lt;td&gt;0.1857&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for-of-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.3440&lt;/td&gt;
&lt;td&gt;0.2963&lt;/td&gt;
&lt;td&gt;0.1987&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.4221&lt;/td&gt;
&lt;td&gt;0.3462&lt;/td&gt;
&lt;td&gt;0.3949&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.0946&lt;/td&gt;
&lt;td&gt;1.0180&lt;/td&gt;
&lt;td&gt;0.1843&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;dd&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/th&gt;
&lt;th&gt;&lt;code&gt;raw-for-loop&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for-of-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.0898&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.3092&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-4.1505&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note that the effect size between &lt;code&gt;array-method&lt;/code&gt; and &lt;code&gt;generator&lt;/code&gt; is 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈−2.1824d \approx -2.1824&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mord"&gt;2.1824&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
: yet another &lt;em&gt;extreme effect&lt;/em&gt; on display.&lt;/p&gt;
&lt;h2&gt;
  
  
  Node.js and Deno: One and the Same
&lt;/h2&gt;

&lt;p&gt;Let's go back to the observation earlier that Node.js and Deno exhibit the same performance characteristics. The following figure superimposes the Deno histogram over the Node.js histogram. The overlap is quite impressive to say the least.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0to170lbrn6wi2yd52g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq0to170lbrn6wi2yd52g.png" alt="Comparison between the Node.js results and the Deno results showing significant overlap" width="600" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's quantify &lt;em&gt;exactly&lt;/em&gt; how much they overlap by considering the effect sizes of corresponding experiment cases.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Experiment&lt;/th&gt;
&lt;th&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;dd&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;raw-for-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.0219&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for-of-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.0356&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.0426&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.0388&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In all cases, there is little to no effect between Node.js and Deno. If we &lt;em&gt;must&lt;/em&gt; draw a conclusion, though, we can see that Node.js is &lt;em&gt;marginally&lt;/em&gt; slower than Deno except in the &lt;code&gt;for-of-loop&lt;/code&gt; case. Nevertheless, this is already well within the realm of noise, so let's not look too deep into it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bun Results
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p31ft8oztsyi092666z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p31ft8oztsyi092666z.png" alt="Histogram of the Bun Results" width="596" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the JavaScriptCore engine enters the scene, the Bun histogram takes on a &lt;em&gt;completely&lt;/em&gt; different shape. I can already hear the Zig fans rejoicing as their results practically blow Node.js and Deno out of the water.&lt;/p&gt;

&lt;p&gt;A cursory inspection of the histograms already shows more stable performance characteristics in JavaScriptCore than in V8. The curves are closer together, but still exhibit the same patterns as in Node.js and Deno—albeit at a smaller magnitude. The table below summarizes the relevant statistics from the experiments.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Experiment&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Standard Deviation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;raw-for-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.2786&lt;/td&gt;
&lt;td&gt;0.2626&lt;/td&gt;
&lt;td&gt;0.2749&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for-of-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.2789&lt;/td&gt;
&lt;td&gt;0.2644&lt;/td&gt;
&lt;td&gt;0.2718&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.3608&lt;/td&gt;
&lt;td&gt;0.2707&lt;/td&gt;
&lt;td&gt;0.3274&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.4919&lt;/td&gt;
&lt;td&gt;0.4712&lt;/td&gt;
&lt;td&gt;0.2651&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rather than rehashing the discussion as in the Node.js and Deno sections, let's instead examine the Bun data based on its similarities and differences from the previous two runtimes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Like Node.js and Deno, the performance degradation with respect to the &lt;code&gt;raw-for-loop&lt;/code&gt; baseline is ordered as &lt;code&gt;for-of-loop&lt;/code&gt;, &lt;code&gt;array-method&lt;/code&gt;, and &lt;code&gt;generator&lt;/code&gt;. This phenomenon where &lt;code&gt;generator&lt;/code&gt; performs worst—much to my dismay and chagrin—is consistent with all engines.&lt;/li&gt;
&lt;li&gt;Unlike that of Node.js and Deno, the Bun distributions are closer together—indicating more stable performance characteristics.&lt;/li&gt;
&lt;li&gt;Bun (JavaScriptCore) optimizes the underlying state machines of the &lt;code&gt;generator&lt;/code&gt; implementation better than Node.js and Deno (V8). &lt;em&gt;By how much, you may ask?&lt;/em&gt; Between Node.js and Bun, the effect size is 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈2.5370d \approx 2.5370&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2.5370&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. Meanwhile, between Deno and Bun, the effect size is 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈2.6401d \approx 2.6401&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;2.6401&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. That is to say, both Node.js and Deno perform &lt;em&gt;extremely&lt;/em&gt; worse than Bun.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next table summarizes the effect sizes of each experiment on the &lt;code&gt;raw-for-loop&lt;/code&gt; baseline.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;dd&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/th&gt;
&lt;th&gt;&lt;code&gt;raw-for-loop&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;for-of-loop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.0012&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;array-method&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.2722&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generator&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;-0.7898&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Like Node.js and Deno, the &lt;code&gt;for-of-loop&lt;/code&gt; is practically equivalent in performance characteristics to the &lt;code&gt;raw-for-loop&lt;/code&gt; baseline.&lt;/li&gt;
&lt;li&gt;Like Node.js and Deno, a similarly &lt;em&gt;small&lt;/em&gt; effect size has been observed between &lt;code&gt;raw-for-loop&lt;/code&gt; and &lt;code&gt;array-method&lt;/code&gt;. Indeed, the performance overhead is &lt;em&gt;small&lt;/em&gt; but certainly non-zero.&lt;/li&gt;
&lt;li&gt;Unlike Node.js and Deno, the overhead of the &lt;code&gt;generator&lt;/code&gt; case only tiptoes between the &lt;em&gt;medium&lt;/em&gt; and &lt;em&gt;large&lt;/em&gt; effect sizes, whereas the former exhibited &lt;em&gt;extreme&lt;/em&gt; effect sizes. This result attests to the previously discussed stability of Bun's performance characteristics.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Now how do array methods and generators compare in Bun?&lt;/em&gt; Between &lt;code&gt;array-method&lt;/code&gt; and &lt;code&gt;generator&lt;/code&gt;, the effect size is &lt;em&gt;medium&lt;/em&gt; with 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;d≈−0.4399d \approx -0.4399&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≈&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;−&lt;/span&gt;&lt;span class="mord"&gt;0.4399&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/p&gt;
&lt;h1&gt;
  
  
  Interpretations and Conclusions
&lt;/h1&gt;

&lt;p&gt;The most glaring conclusion thus far is that I was comically wrong about generators and chained array methods. In all experiments across all runtimes, the &lt;code&gt;generator&lt;/code&gt; case consistently performed the &lt;strong&gt;worst&lt;/strong&gt;. To add salt to the wound, I was not even wrong by a &lt;em&gt;small&lt;/em&gt; margin, but by an &lt;em&gt;extreme&lt;/em&gt; margin! Truly a hard lesson learned: &lt;strong&gt;measure, measure, measure.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Importance of Spatial and Temporal Locality
&lt;/h2&gt;

&lt;p&gt;I suspect that these results are due to the heavily optimized C++ implementations that underpin &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt;. Specifically, since arrays are &lt;em&gt;contiguous&lt;/em&gt; data structures, low-level caches and memory prefetchers (in hardware and software) exploit the spatial and temporal locality of the array operations. In other words, a tight loop over 32768 integers becomes light work for hardware that can fetch and process 32 KiB &lt;strong&gt;in bulk&lt;/strong&gt; without invalidating its internal caches.&lt;/p&gt;

&lt;p&gt;Consider the alternative: generators. Generators are implicit state machines that tick forward after every &lt;code&gt;yield&lt;/code&gt;. There is no notion of contiguity here because the values that will be processed are yet to be yielded by the generator. That alone fundamentally hampers the spatial and temporal locality of array operations. The state machine must necessarily tick &lt;em&gt;one iteration at a time&lt;/em&gt;. This is opposed to the C++ code of &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;map&lt;/code&gt; that can zoom through the ready data in one fell swoop—albeit in two iterations.&lt;/p&gt;

&lt;p&gt;In practice, this means that the 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(2n)O(2n)&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 time complexity of &lt;code&gt;filter&lt;/code&gt; + &lt;code&gt;map&lt;/code&gt; does not tell the whole story. Although generators are single-pass 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n)O(n)&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 constructs, sacrificing spatial and temporal locality incurs an &lt;em&gt;extreme&lt;/em&gt; overhead that more than makes up for the two-pass bulk operation of &lt;code&gt;filter&lt;/code&gt; + &lt;code&gt;map&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As we chain more array methods (which is rarely necessary), we anticipate &lt;code&gt;array-method&lt;/code&gt; eventually surpassing &lt;code&gt;generator&lt;/code&gt; in execution times.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; Until then, we have shown that the overhead of generators due to (implicit state machines) proves to be too costly.&lt;/p&gt;

&lt;p&gt;Some part of me is quite relieved that this is the case. I must admit that &lt;code&gt;filter&lt;/code&gt; + &lt;code&gt;map&lt;/code&gt; chains read more elegantly than generators (even with helpers from &lt;a href="https://www.npmjs.com/package/itertools" rel="noopener noreferrer"&gt;&lt;code&gt;itertools&lt;/code&gt;&lt;/a&gt;). At least I can now rest assured that generator gymnastics need not apply.&lt;/p&gt;
&lt;h2&gt;
  
  
  V8 versus JavaScriptCore
&lt;/h2&gt;

&lt;p&gt;An unexpected storyline that unraveled as I performed the experiments was the lopsided battle between V8 and JavaScriptCore. I have heard about Bun's supposedly superior performance versus Node.js and Deno, but I have only experienced it in the making of this article. The effect sizes are less impressive in the &lt;code&gt;raw-for-loop&lt;/code&gt;, &lt;code&gt;for-of-loop&lt;/code&gt;, and &lt;code&gt;array-method&lt;/code&gt; cases. Where Bun really shined was with the &lt;code&gt;generator&lt;/code&gt; case and the overall stability of its performance characteristics.&lt;/p&gt;

&lt;p&gt;Frankly, I am quite impressed by Bun and especially JavaScriptCore. To beat the formidable V8 engine by &lt;em&gt;extreme&lt;/em&gt; margins is no small feat. For that, I will continue to keep a close eye on Bun. I look forward to seeing how far we can push the boundaries of JavaScript.&lt;/p&gt;
&lt;h2&gt;
  
  
  So... when to use generators then?
&lt;/h2&gt;

&lt;p&gt;Generators still have their place where lazy computation is a necessity due to memory constraints. One notable example is file streaming, where it's impractical to load an entire file or response into memory (as is typically the case in cloud environments).&lt;/p&gt;

&lt;p&gt;More generally speaking, generators shine in environments that are bottlenecked by idle times due to I/O (e.g., file system, networks, user inputs, streams, etc.). Here, CPU performance is less relevant because the CPU would be idle waiting on I/O to respond anyway. The lazy computation keeps memory usage low while data streaming ensures that clients receive data as soon as possible.&lt;/p&gt;

&lt;p&gt;However, there is another compelling reason to use generators: &lt;strong&gt;composability&lt;/strong&gt;. Because generators are lazily executed, operations on the resulting data stream are easily composable as items are processed one at a time. The popular &lt;a href="https://www.npmjs.com/package/itertools" rel="noopener noreferrer"&gt;&lt;code&gt;itertools&lt;/code&gt;&lt;/a&gt; package—which features a plethora of iteration utilities—is a testament to this fact.&lt;/p&gt;

&lt;p&gt;In fact, the developer experience around iteration utilities is so great that there is an active &lt;a href="https://tc39.es/proposal-iterator-helpers/" rel="noopener noreferrer"&gt;Stage 3 ECMAScript proposal&lt;/a&gt; right now (as of writing) that aims to officially add lazy iterator helpers to the language. When this is more widely supported, expect a follow-up article to this one that investigates the would-be C++-backed helpers.&lt;/p&gt;
&lt;h1&gt;
  
  
  Future Work
&lt;/h1&gt;

&lt;p&gt;As thorough as I have been in this research, there is still some more work to be done. Here are a few bullets that were previously mentioned in the article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reproduce these experiments on a native Linux machine.&lt;/li&gt;
&lt;li&gt;Investigate whether a sufficiently long chain of array methods eventually surpass the execution time of the equivalent generator.&lt;/li&gt;
&lt;li&gt;Compare the performance characteristics of the upcoming &lt;a href="https://tc39.es/proposal-iterator-helpers/" rel="noopener noreferrer"&gt;iterator helpers&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repository for all the scripts, notebooks, results, and analyses is available below.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/BastiDood" rel="noopener noreferrer"&gt;
        BastiDood
      &lt;/a&gt; / &lt;a href="https://github.com/BastiDood/js-generators-vs-array-methods" rel="noopener noreferrer"&gt;
        js-generators-vs-array-methods
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The repository for all the scripts, notebooks, results, and analyses related to my experiments on JavaScript generators and chained array methods.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;JavaScript Generators vs. Array Methods&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;The repository for all the scripts, notebooks, results, and analyses related to my experiments on JavaScript generators and chained array methods. See the full article &lt;a href="https://dev.to/somedood/i-was-wrong-about-array-methods-and-generators-2ig9" rel="nofollow"&gt;"I was wrong about array methods and generators..."&lt;/a&gt; for more details on the methodology, results, interpretations, and conclusions.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Generating Random Bytes&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The first step is to generate 32 KiB of random data. There are many ways to do this, but I opted to generate them via the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;Crypto#getRandomValues&lt;/code&gt;&lt;/a&gt; function in JavaScript. A Deno script is already available at &lt;a href="https://github.com/BastiDood/js-generators-vs-array-methodsrandom/random.js" rel="noopener noreferrer"&gt;&lt;code&gt;random/random.js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; This will overwrite the already existing `random.bin` file!&lt;/span&gt;
deno run random/random.js&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Running the Experiments&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Node.js&lt;/span&gt;
&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;run&lt;/span&gt; () { node --experimental-default-type=module benchmark/bench.node.js &lt;span class="pl-smi"&gt;$1&lt;/span&gt; &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; notebook/node/&lt;span class="pl-smi"&gt;$1&lt;/span&gt;.csv&lt;span class="pl-k"&gt;;&lt;/span&gt; }
run raw-for-loop
run for-of-loop
run array-method
run generator&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Deno&lt;/span&gt;
&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;run&lt;/span&gt; () { deno --quiet --allow-read --allow-hrtime benchmark/bench.deno.js -- &lt;span class="pl-smi"&gt;$1&lt;/span&gt; &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; notebook/deno/&lt;span class="pl-smi"&gt;$1&lt;/span&gt;.csv&lt;span class="pl-k"&gt;;&lt;/span&gt; }
run raw-for-loop&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/BastiDood/js-generators-vs-array-methods" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;While you're there, please don't forget to &lt;a href="https://github.com/BastiDood/js-generators-vs-array-methods" rel="noopener noreferrer"&gt;star the repository&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/BastiDood/js-generators-vs-array-methods" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Star the Repository&lt;/a&gt;
&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;However, this is yet to be shown experimentally as it is already beyond the scope of this article. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>computerscience</category>
      <category>datascience</category>
    </item>
    <item>
      <title>A Compelling Case for the Comma Operator</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Fri, 06 Sep 2024 21:28:36 +0000</pubDate>
      <link>https://dev.to/somedood/a-compelling-case-for-the-comma-operator-28bn</link>
      <guid>https://dev.to/somedood/a-compelling-case-for-the-comma-operator-28bn</guid>
      <description>&lt;p&gt;The &lt;strong&gt;comma operator&lt;/strong&gt; is one of the lesser-known operators in C-like languages such as JavaScript and C++. Essentially, it delimits a sequence of expressions and only returns the result of the final one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's natural to ask then: &lt;em&gt;when would it ever be useful to cram multiple expressions in a single line?&lt;/em&gt; Furthermore, even if it were useful, why would a comma-separated sequence of expressions (in a single line) be more readable and maintainable than a semicolon-separated sequence of statements (across several lines)? When should we prefer one over the other?&lt;/p&gt;

&lt;p&gt;These are questions that I have struggled to answer over the years, but now I think I finally have an answer. In this article, I present a compelling case—perhaps the only one frankly speaking—for the comma operator.&lt;/p&gt;

&lt;h1&gt;
  
  
  A Motivating Example
&lt;/h1&gt;

&lt;p&gt;Let's first talk about the conditional ternary operator. As seen below, if the &lt;code&gt;condition&lt;/code&gt; is truthy, it &lt;em&gt;evaluates&lt;/em&gt; &lt;code&gt;value&lt;/code&gt;. Otherwise, it &lt;em&gt;evaluates&lt;/em&gt; &lt;code&gt;another&lt;/code&gt;. There is emphasis in the key word "evaluation" here because the branches only execute when their condition is met.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For most cases, it's neat and pretty. Where it falls apart, however, is when we need to do more complex logic in between the branches &lt;em&gt;before&lt;/em&gt; returning the conditional value. At this point, we resort to this unfortunate perversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Uninitialized! Yikes!&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do some complex stuff in between...&lt;/span&gt;
    &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Actual Assignment&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do other complex stuff in between...&lt;/span&gt;
    &lt;span class="nf"&gt;doAnotherThing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Actual Assignment&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Hopefully we didn't forget to initialize `result`!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now there are many issues with this formulation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;result&lt;/code&gt; is uninitialized at first. This is not inherently evil, but an easy tried-and-tested way to avoid bugs due to &lt;code&gt;undefined&lt;/code&gt; is to just always initialize variables.&lt;/li&gt;
&lt;li&gt;The initialization of &lt;code&gt;result&lt;/code&gt; is literally at the bottom of the branch—far detached from its declaration.&lt;/li&gt;
&lt;li&gt;By the end of the conditional, we better hope that &lt;code&gt;result&lt;/code&gt; is surely initialized. If not us, we better hope that our teammates equally enforce that. If not now, we better hope that future developers uphold that, too!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is a way around this limitation if we insist on using conditional ternary expressions. We just have to refactor the code into functions. That's definitely easier said than done. This gimmick gets old real quick!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;computeWrappedValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;computeWrappedAnother&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// How cumbersome!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;computeWrappedValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;computeWrappedAnother&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expression-based programming languages (such as Rust) have a more elegant solution. By reclassifying the &lt;code&gt;if&lt;/code&gt; &lt;strong&gt;statement&lt;/strong&gt; as an &lt;code&gt;if&lt;/code&gt; &lt;strong&gt;expression&lt;/strong&gt;, each branch can be evaluated and thus return values that can later be stored in a variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// A conditional ternary operator thus looks like this. Each branch&lt;/span&gt;
&lt;span class="c1"&gt;// returns a value, which is captured by the `result` variable.&lt;/span&gt;
&lt;span class="c1"&gt;// We thus ensure that `result` is always initialized by construction.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;another&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If we wanted to do something more complex, we use the same syntax.&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// In Rust, the last expression without a semicolon is the value&lt;/span&gt;
    &lt;span class="c1"&gt;// that will be "returned" by the overall `if` expression.&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;do_another_thing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;another&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Can we emulate this in C-like languages?&lt;/em&gt; You've likely long foreseen where I'm headed with this, but yes!&lt;/p&gt;

&lt;h1&gt;
  
  
  A Compelling Case
&lt;/h1&gt;

&lt;p&gt;What we want is a way to arbitrarily execute statements &lt;em&gt;before&lt;/em&gt; returning a value within the ternary branches. Well, lucky for us, this is &lt;em&gt;exactly&lt;/em&gt; what the comma operator is for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Parenthesized for clarity.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;condition&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;// evaluates to `value`&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;doAnotherThing&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// evaluates to `another`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The neat thing about this formulation is the fact that the branch expressions are only evaluated when necessary. We effectively emulate the behavior of expression-based programming languages. Gone are the days of ad hoc wrapper functions!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But alas,&lt;/em&gt; we can only go so far with this technique. You can imagine that for some sufficiently large &lt;code&gt;n&lt;/code&gt;, cramming &lt;code&gt;n&lt;/code&gt; statements into a single line already begs to be refactored into its own function. Personally, I would already reconsider by the time &lt;code&gt;n &amp;gt; 3&lt;/code&gt;. Anything higher than that is dubious construction in terms of readability.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Maybe we should reconsider here?&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;condition&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;world&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;doAnotherThing&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Okay, stop. Definitely turn back now!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;condition&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nf"&gt;doMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;doEvenMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;world&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nf"&gt;doAnotherThing&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="nf"&gt;doMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;doEvenMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;another&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Unless, of course, you're fine with this. It kinda does&lt;/span&gt;
&lt;span class="c1"&gt;// look like a Rust `if` expression if you squint hard enough.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Wrapping up, we have seen a compelling case for the comma operator: complex conditional ternary operations. The comma operator shines when the branches are short and sweet, but falls out of fashion real quick after three inlined statements. At that point, one is likely better off refactoring the code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So should you use comma operators?&lt;/em&gt; Honestly... yeah! Readable code is mindful of the next reader, so as long as the comma chains are never egregiously long, I would accept—and even encourage—this coding style. If we consider the alternatives (i.e., uninitialized variables and refactored micro-functions), the comma operator is not so bad after all.&lt;/p&gt;

&lt;p&gt;In practice, I already sprinkle my own codebases with these funny-looking comma operators. Though in fairness, I rarely have a need for multi-statement ternary conditionals anyway. But when I do, I have a cool tool in my belt that concisely expresses my intent.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;To that end, I rest my compelling case for the comma operator.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>javascript</category>
      <category>rust</category>
      <category>c</category>
    </item>
    <item>
      <title>Bitmasks are not so esoteric and impractical after all...</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Sat, 20 Jul 2024 07:08:16 +0000</pubDate>
      <link>https://dev.to/somedood/bitmasks-are-not-so-esoteric-and-impractical-after-all-55o6</link>
      <guid>https://dev.to/somedood/bitmasks-are-not-so-esoteric-and-impractical-after-all-55o6</guid>
      <description>&lt;p&gt;So an overly flashy title from one of my articles six years ago finally bit me in the back side... 😅&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1814166076990558259-912" src="https://platform.twitter.com/embed/Tweet.html?id=1814166076990558259"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1814166076990558259-912');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1814166076990558259&amp;amp;theme=dark"
  }



&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/somedood" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F108756%2F1bb8b570-520b-4ad9-8a25-ee28c4d04a8d.jpeg" alt="somedood"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/somedood/bitmasks-a-very-esoteric-and-impractical-way-of-managing-booleans-1hlf" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Bitmasks: A very esoteric (and impractical) way of managing booleans&lt;/h2&gt;
      &lt;h3&gt;Basti Ortiz ・ Oct 28 '18&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#computerscience&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;In my defense, this was written by my naive 2018 self. Six years and one computer science degree later, I have vastly changed my perspective on this. This is why we are going in the completely opposite direction. In this article, we will discuss why bitmasks are not so esoteric and impractical after all.&lt;/p&gt;

&lt;h1&gt;
  
  
  Parallelized Truth-Checking
&lt;/h1&gt;

&lt;p&gt;Let's go back to the example used in the original article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;isOnline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;isFullscreen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hasAudio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hasPremiumAccount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;canSendTelemetry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose that we are tasked to check if all of these flags are &lt;code&gt;true&lt;/code&gt;. In a world without bitmasks, we may end up with the following solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAllTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;flag&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// ALTERNATE:&lt;/span&gt;
    &lt;span class="c1"&gt;// return flags.every(flag =&amp;gt; flag);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;isAllTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is great and all. Some may even consider its alternate one-line version the epitome of clean JavaScript code. After all, who could say no to the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every" rel="noopener noreferrer"&gt;&lt;code&gt;Array#every&lt;/code&gt;&lt;/a&gt; method?&lt;/p&gt;

&lt;p&gt;But unfortunately, as we increase the number of flags in &lt;code&gt;config&lt;/code&gt;, our &lt;code&gt;O(n)&lt;/code&gt; solution eventually shows its cracks. Of course in practice, it is rare for a &lt;code&gt;config&lt;/code&gt; object to scale up to a million flags. At that point, there are bigger architectural decisions that need to be reconsidered.&lt;/p&gt;

&lt;p&gt;Nevertheless, for the sake of argument, we are left asking: &lt;em&gt;is there a more efficient way to do this?&lt;/em&gt; Yes, as a matter of fact, there &lt;em&gt;is&lt;/em&gt; an &lt;code&gt;O(1)&lt;/code&gt; solution to this problem: bitmasks!&lt;/p&gt;

&lt;p&gt;Bitmasks enable us to simultaneously query all of the bits in an integer in a single CPU instruction. Since we are interested in checking if all the bits are turned on, we simply have to apply a bitwise-&lt;code&gt;AND&lt;/code&gt; on an all-ones bitmask (i.e., &lt;code&gt;0b1111...1111&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ASSUME: We have a way to convert the&lt;/span&gt;
&lt;span class="c1"&gt;// `config` to its bitwise representation.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAllTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Explicitly convert to an integer just in case.&lt;/span&gt;
    &lt;span class="c1"&gt;// https://tc39.es/ecma262/#sec-numberbitwiseop&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Obtain a bitmask where all bits are ones.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BITMASK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// The bitwise-AND with the `BITMASK` verifies&lt;/span&gt;
    &lt;span class="c1"&gt;// whether the `bits` are all ones (i.e., all true).&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;BITMASK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;BITMASK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that optimization, we now have a constant-time checker that can simultaneously check &lt;a href="https://tc39.es/ecma262/#sec-toint32" rel="noopener noreferrer"&gt;32 bits&lt;/a&gt; (a.k.a. 32 Boolean values) in a single CPU instruction. This is &lt;strong&gt;much&lt;/strong&gt; better than our original linear-time solution, which went through &lt;em&gt;each bit one at a time&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now you may ask: &lt;em&gt;what if we have more than 32 Boolean values?&lt;/em&gt; Fortunately, some languages (such as JavaScript and Python) support arbitrarily-sized integers, which effectively remove the 32-bit limit. That is to say, we can operate on any finite number of flag bits and bit masks. Specifically for JavaScript, we have the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt" rel="noopener noreferrer"&gt;&lt;code&gt;BigInt&lt;/code&gt;&lt;/a&gt; type.&lt;/p&gt;

&lt;p&gt;For other lower-level languages that only have fixed-size integers (such as C, C++, Rust, and Zig), there is no magical way to extend this algorithm to more than the maximum number of bits that the language supports. Luckily for us, we can still at least "chunk" the input into 32-bit groups. In fact, this is how arbitrarily-sized integer operations are implemented under the hood.&lt;/p&gt;

&lt;p&gt;Note that the algorithm would still be linear-time, but it is at least 32 times faster than iterating one bit at a time! This is not to even mention the removal of the &lt;code&gt;for&lt;/code&gt;-loop overhead (e.g., branch instructions, jump instructions, etc.).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {bigint} flags - The bit flags stored as one big integer.
 * @param {bigint} count - The actual number of bits in {@linkcode flags}.
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAllTrue_Chunked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BITMASK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 32 ones&lt;/span&gt;
    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Only consider the first 32 bits for this chunk.&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;BITMASK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;BITMASK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Advance the cursor.&lt;/span&gt;
        &lt;span class="nx"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analogously, we can also apply this algorithm to the bitwise-&lt;code&gt;OR&lt;/code&gt; operator, which now checks if &lt;em&gt;at least one bit&lt;/em&gt; is turned on rather than checking if &lt;em&gt;all bits&lt;/em&gt; are turned on. The point is: bitwise operations enable us to write highly parallelized Boolean queries.&lt;/p&gt;

&lt;h1&gt;
  
  
  Struct-Packing for Network Efficiency
&lt;/h1&gt;

&lt;p&gt;Another neat use case for bitmasks is querying the bit flags in a tightly packed &lt;code&gt;struct&lt;/code&gt;. This is especially relevant in computer networking, where data packets are typically serialized as a literal &lt;code&gt;struct&lt;/code&gt;. For instance, one may represent the &lt;a href="https://datatracker.ietf.org/doc/html/rfc9293#name-header-format" rel="noopener noreferrer"&gt;header of a Transmission Control Protocol (TCP) segment&lt;/a&gt; as a &lt;code&gt;struct&lt;/code&gt; with the following fields:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;tcp_header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;src_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;dst_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;seq_number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;ack_number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;data_offset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;reserved&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;window_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;checksum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;urgent_pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of particular interest is the &lt;code&gt;flags&lt;/code&gt; field, which is essentially an array of bits that indicate whether the packet is a &lt;code&gt;SYN&lt;/code&gt;, &lt;code&gt;ACK&lt;/code&gt;, &lt;code&gt;FIN&lt;/code&gt;, or &lt;code&gt;RST&lt;/code&gt; packet (among other bit flags). The specifics of the protocol is beyond the scope of this article, so we instead explore &lt;em&gt;why&lt;/em&gt; a TCP header uses an 8-bit integer for bit flags rather than individual &lt;code&gt;bool&lt;/code&gt; fields.&lt;/p&gt;

&lt;p&gt;It is important to first consider that a &lt;code&gt;bool&lt;/code&gt; in C is essentially an 8-bit integer that can only be either &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;1&lt;/code&gt;. Although a single bit is sufficient (and necessary!) to represent &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;true&lt;/code&gt;, the C standard still requires that a &lt;code&gt;bool&lt;/code&gt; is 8 bits wide (where 7 bits are left unused).&lt;/p&gt;

&lt;p&gt;From the perspective of network efficiency, an array of &lt;code&gt;bool&lt;/code&gt; is therefore terrible packet design! That is to say, an array of &lt;code&gt;bool&lt;/code&gt; values requires 8 bits &lt;em&gt;per flag&lt;/em&gt;. With the &lt;code&gt;tcp_header.flags&lt;/code&gt; field containing 8 flags, we would require 64 bits just to represent them in a &lt;code&gt;struct&lt;/code&gt;! These bandwidth inefficiencies add up at the unfathomable scale and volume of data transfers in the Internet.&lt;/p&gt;

&lt;p&gt;The solution is &lt;code&gt;struct&lt;/code&gt;-packing. Instead of wasting 7 bits per &lt;code&gt;bool&lt;/code&gt; field, we should instead "pack" the eight bit flags as a single 8-bit integer. We then use bitmasking to query and extract each field of interest. And just like that, we saved ourselves from 56 unused bits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;CWR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 1000_0000&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;ECE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0100_0000&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;URG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0010_0000&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;ACK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0001_0000&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;PSH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x08&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0000_1000&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;RST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x04&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0000_0100&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;SYN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x02&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0000_0010&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;FIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x01&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0000_0001&lt;/span&gt;

&lt;span class="c1"&gt;// Is this a SYN packet?&lt;/span&gt;
&lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;SYN&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SYN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Is this an ACK packet?&lt;/span&gt;
&lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ACK&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Is this a SYN-ACK packet?&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;SYN_ACK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SYN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;SYN_ACK&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;SYN_ACK&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Caching with Bloom Filters
&lt;/h1&gt;

&lt;p&gt;Following the theme of &lt;code&gt;struct&lt;/code&gt;-packing, bitmasks once again show up in systems that require efficient caching strategies. Chief among the use cases are content delivery networks (CDNs) and database systems.&lt;/p&gt;

&lt;p&gt;But first, let's go back to what a cache is for. When certain operations are too expensive to run frequently, a cache is responsible for intercepting inputs and checking whether a corresponding &lt;em&gt;previously&lt;/em&gt; computed output may be returned instead.&lt;/p&gt;

&lt;p&gt;Now let's consider a case study on web servers. Nowadays, many web servers dynamically render HTML on the fly depending on the current state of some internal database. Sometimes, this dynamic generation may be expensive. Perhaps the database query is a non-trivial aggregation over millions of rows. Perhaps an external API invocation takes a long time to process the request. Perhaps an upload is taking too long.&lt;/p&gt;

&lt;p&gt;In any case, a cache layer may prove to yield significant performance gains on the system. &lt;em&gt;But what exactly are we caching?&lt;/em&gt; A simple example for the sake of demonstration is a parameterized web page whose contents depend on a portion of the URL—say &lt;code&gt;/user/:id&lt;/code&gt;. As much as possible, suppose that we would like to avoid frequently generating user profiles. Hence, the only sensible time to rerender is after the user modifies their profile. Everything is served from a CDN cache otherwise.&lt;/p&gt;

&lt;p&gt;A naive in-memory cache in the web server could store the URLs (e.g., &lt;code&gt;/user/100&lt;/code&gt;) of known cached pages in a set-like data structure. If a URL exists in the cache, then serve from the CDN. Otherwise, we generate the HTML page from scratch. Sadly, this design comes at the cost of higher memory usage. Imagine having to cache &lt;code&gt;/user/1&lt;/code&gt; all the way up to &lt;code&gt;/user/1000000&lt;/code&gt;. &lt;em&gt;Yikes!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A more memory-efficient way to cache this knowledge in-memory (without blowing up RAM) is through a Bloom filter. Instead of caching &lt;em&gt;all&lt;/em&gt; of the known &lt;code&gt;id&lt;/code&gt; values of cached pages, a Bloom filter caches only a &lt;em&gt;subset&lt;/em&gt; of these &lt;code&gt;id&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;We thus set up the Bloom filter in such a way that if the &lt;em&gt;hash&lt;/em&gt; of a URL gets a cache hit, then we know that the corresponding user &lt;em&gt;may&lt;/em&gt; have modified their profile (which should be rare in practice). Otherwise, we know &lt;em&gt;for certain&lt;/em&gt; that no such modifications have taken place yet, so it is safe to serve from the CDN cache directly.&lt;/p&gt;

&lt;p&gt;In theory, we may implement a Bloom filter as an array of Boolean values. The URLs must then be hashed as a valid index into that array. Alternatively, as it is the theme of this article, we may use bitmasks instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bloomFilterHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Extract the :id from the URL.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lastIndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:id not found!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// This is a simple hash where we simply take the ID modulo 32.&lt;/span&gt;
    &lt;span class="c1"&gt;// This always gives us a valid index into a 32-bit Bloom filter.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initially zeroed 32-bit Bloom filter.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;bloomFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// GET handler for the /user/:id.&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/user/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Hash the URL as an index into the Bloom filter.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bloom&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bloomFilterHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bitmask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bloomFilter&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;bitmask&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;bitmask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// The bit is turned off. Therefore, no modifications&lt;/span&gt;
        &lt;span class="c1"&gt;// have been made before. We can use the cached profile.&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// The bit is turned on, which means one of the (possibly many)&lt;/span&gt;
    &lt;span class="c1"&gt;// users that computed this hash has modified their profile.&lt;/span&gt;
    &lt;span class="c1"&gt;// Time to generate a brand new profile page. Ideally, we should&lt;/span&gt;
    &lt;span class="c1"&gt;// eventually clear the Bloom filter so that future requests&lt;/span&gt;
    &lt;span class="c1"&gt;// need not pay this overhead (even though it should be rare).&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchUserProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateProfileHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// POST handler for modifying user profiles.&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/user/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Hash the URL as an index into the Bloom filter.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bloom&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bloomFilterHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bitmask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;bloom&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Mark the Bloom filter bit as "dirty" (i.e., modified).&lt;/span&gt;
    &lt;span class="nx"&gt;bloomFilter&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="nx"&gt;bitmask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;modifyUserProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/somedood/bitmasks-a-very-esoteric-and-impractical-way-of-managing-booleans-1hlf"&gt;original article&lt;/a&gt; that started this all, I framed bitmasks as an "esoteric" and "impractical" way to "over-engineer" Boolean values that only "hardcore computer scientists" should care about. Much of that negative sentiment and gatekeeping has gone away nowadays as I've grown as a mentor, a software engineer, and a computer scientist myself. In its place is a greater appreciation for the attention to detail involved in such low-level optimizations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"[Bitmasking] is impractical and unreadable most of the time. Constant documentation and awareness are required to make sure that the correct bits are being selected and manipulated."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Though if there's anything worth saving from the original article, I still stand by my concerns on readability and maintainability. Without clear documentation, bitmasks look like magic numbers out of thin air. The runic soup of bitwise operators doesn't make the situation better either given its seemingly arbitrary incantations of tildes and minuses.&lt;/p&gt;

&lt;p&gt;Wherever possible (and perhaps until performance bottlenecks arise), it is wiser to keep bitmasks as a last-resort tool in our belt. The cognitive overhead necessary in deciphering bitwise logic is frankly unappealing in many cases.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Frankly, I wouldn't recommend using [bitmasks] regularly, if at all. As clever as it is, it is just too esoteric for common use... Overall, there aren't many applications for this, especially in a high-level language like JavaScript."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Parallelized truth-checking, &lt;code&gt;struct&lt;/code&gt;-packing, probabilistic caching, bit fields, permission bits, and pattern matching are just a few examples of the more "practical" side of bitmasks in the real world. Even in high-level languages such as JavaScript, bitmasks are in fact &lt;em&gt;not&lt;/em&gt; just mere intellectual play among "hardcore computer scientists".&lt;/p&gt;

&lt;p&gt;Much like design patterns, data structures, and algorithms, the humble bitmask serves as one of the many tricks that we have up our sleeves. As with most things in our practice, it's just a matter of using the right tool for the job while keeping code quality in check.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Just like last time... bitmask responsibly.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>javascript</category>
      <category>c</category>
    </item>
    <item>
      <title>JavaScript First, Then TypeScript</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Sun, 15 Oct 2023 12:38:52 +0000</pubDate>
      <link>https://dev.to/somedood/javascript-first-then-typescript-10bg</link>
      <guid>https://dev.to/somedood/javascript-first-then-typescript-10bg</guid>
      <description>&lt;p&gt;A recent trend has shaken up the JavaScript-TypeScript community: the &lt;strong&gt;anti-build-step movement&lt;/strong&gt;. For over a decade now, a build step&lt;sup id="fnref1"&gt;1&lt;/sup&gt; has been widely considered to be a necessary best practice in modern web development. Now more than ever, this seemingly dogmatic reality of the web development experience has been challenged.&lt;/p&gt;

&lt;p&gt;There are many reasons for this sudden change of heart.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://fresh.deno.dev/" rel="noopener noreferrer"&gt;Fresh&lt;/a&gt; framework by &lt;a href="https://deno.com/" rel="noopener noreferrer"&gt;Deno&lt;/a&gt; cited an &lt;a href="https://deno.com/blog/you-dont-need-a-build-step" rel="noopener noreferrer"&gt;improved developer experience due to tighter feedback loops&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; team followed suit &lt;a href="https://github.com/sveltejs/svelte/pull/8569" rel="noopener noreferrer"&gt;but motivated by the maintainer's developer experience&lt;/a&gt; as they migrated the project away from TypeScript in favor of plain &lt;a href="https://jsdoc.app/" rel="noopener noreferrer"&gt;JSDoc&lt;/a&gt; comments for type annotations instead.&lt;/li&gt;
&lt;li&gt;Most controversially, the &lt;a href="https://turbo.hotwired.dev/" rel="noopener noreferrer"&gt;Turbo&lt;/a&gt; framework &lt;a href="https://world.hey.com/dhh/turbo-8-is-dropping-typescript-70165c01" rel="noopener noreferrer"&gt;dropped TypeScript support&lt;/a&gt; altogether after assessing that strong typing was the culprit behind poor developer experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One common thread ties everything together: &lt;strong&gt;developer experience&lt;/strong&gt;. In this article, however, I will not argue whether TypeScript is still relevant today.&lt;sup id="fnref2"&gt;2&lt;/sup&gt; Instead, I choose to reflect on my own journey of stepping away from TypeScript—but for a completely different reason: &lt;strong&gt;consumer semantics&lt;/strong&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript Need Not Apply
&lt;/h2&gt;

&lt;p&gt;TypeScript prides itself as a superset of JavaScript. As a matter of fact, TypeScript owes much of its success to this key design decision. The classic migration guide for renaming &lt;code&gt;.js&lt;/code&gt; to &lt;code&gt;.ts&lt;/code&gt; considerably lowered the barrier to entry as teams gradually migrated their codebases. But, it is exactly this design decision that also made me realize where TypeScript isn't necessary!&lt;/p&gt;

&lt;p&gt;With TypeScript being a superset of JavaScript, there exists a subset of the TypeScript language that's just plain old JavaScript. As it turns out in my experience, this also happens to be the subset of TypeScript that I deal with most often—especially in application code!&lt;/p&gt;

&lt;p&gt;Consider the following example that features two TypeScript files: &lt;code&gt;add.ts&lt;/code&gt; (simple adder library) and &lt;code&gt;main.ts&lt;/code&gt; (application entry point).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// add.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./add.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;add.ts&lt;/code&gt;, the presence of type annotations makes TypeScript a necessity. On the other hand, a cursory inspection of &lt;code&gt;main.ts&lt;/code&gt; shows us that its syntax is &lt;em&gt;purely&lt;/em&gt; JavaScript! At its current state, &lt;code&gt;main.ts&lt;/code&gt; need not be TypeScript; &lt;code&gt;main.js&lt;/code&gt; is sufficient.&lt;/p&gt;

&lt;p&gt;This central motivating example led me to re-evaluate my relationship with TypeScript. It gradually became apparent to me that TypeScript is best suited for &lt;em&gt;library code&lt;/em&gt; while JavaScript is more appropriate for &lt;em&gt;application code&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; I would like to clarify here that when I say "library code", I do not necessarily mean published NPM packages. "Library code" can refer to internally linked sub-projects in a monorepo/workspace. One may even consider imported files from the same project to be "library code". The point being: "application code" is the consumer of "library code" wherever that may be imported from (e.g., NPM, workspace, files, etc.).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Specifically, consumer code that can solely rely on type inference for type safety (i.e., no type annotations required) may thrive on JavaScript alone. This is not the case for library code which export functions that require type annotations—especially for parameters. One may even take this guideline to the extreme by removing return types from function signatures altogether in favor of return-value type inference. This is generally considered to be poor practice, though.&lt;/p&gt;

&lt;p&gt;Nowadays, I isolate library code more aggressively. One may enforce a scheme (for example) where UI components are consumers written in JavaScript while the more complex business logic, data fetching, and data validation are imported from a TypeScript library. Of course, the libraries may be consumers themselves, in which case they may be written in plain old JavaScript as well.&lt;/p&gt;

&lt;p&gt;Observe that such a scheme is desirable not only because it is a best practice that encourages more testable architectures, but also because it makes the separation between the JavaScript world and the TypeScript world more intentional. That is to say, I &lt;em&gt;choose&lt;/em&gt; to write JavaScript (in consumer code) because type inference is sufficient. But, I also &lt;em&gt;choose&lt;/em&gt; to write TypeScript everywhere else when type annotations, type aliases, and interfaces are necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript First, Then TypeScript
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;.js&lt;/code&gt; extension is no longer an indicator of antiquity, but a declaration of sufficiency in language semantics. I prefer to write plain old JavaScript because the &lt;code&gt;.js&lt;/code&gt; extension presents itself as &lt;em&gt;consumer code&lt;/em&gt;. The &lt;code&gt;.js&lt;/code&gt; extension is a deliberate communication of the consumer semantics.&lt;/p&gt;

&lt;p&gt;For more advanced cases, I &lt;em&gt;upgrade&lt;/em&gt; from &lt;code&gt;.js&lt;/code&gt; to &lt;code&gt;.ts&lt;/code&gt;, but keep the TypeScript surface as minimal as possible while isolating it from the rest of the application code. Arguably, this is exactly what &lt;a href="https://www.typescriptlang.org/docs/handbook/2/type-declarations.html#dts-files" rel="noopener noreferrer"&gt;&lt;code&gt;.d.ts&lt;/code&gt; declaration files&lt;/a&gt; are for, but I admittedly find that the developer experience for inline implementation files is more ergonomic (and less error-prone!) than duplicating function signatures in &lt;code&gt;.js&lt;/code&gt; and &lt;code&gt;.d.ts&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;Overall, I still strongly believe in TypeScript's value to the JavaScript ecosystem.&lt;sup id="fnref3"&gt;3&lt;/sup&gt; Nowadays, I just choose to write JavaScript first wherever possible, then &lt;em&gt;upgrade&lt;/em&gt; to TypeScript as a last resort.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;This includes all sorts of transpiling, compiling, tree-shaking, code-splitting, bundling, etc. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;In fact, I am a huge fan of the type-safety conveniences and guarantees that TypeScript enables. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Even without the TypeScript syntax, the benefits of type safety also extends to JSDoc annotations (which are powered by TypeScript analysis anyway). ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>🤖 Svelte Reviewed: A Masterclass on Empowerment 🤖</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Mon, 11 Sep 2023 09:03:34 +0000</pubDate>
      <link>https://dev.to/somedood/svelte-reviewed-a-masterclass-on-empowerment-2544</link>
      <guid>https://dev.to/somedood/svelte-reviewed-a-masterclass-on-empowerment-2544</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Cybernetically enhanced web apps.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A most interesting tagline for the &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; framework &lt;a href="https://svelte.dev/blog/svelte-3-rethinking-reactivity#new-look" rel="noopener noreferrer"&gt;since version 3&lt;/a&gt;. The Svelte team prides itself in aggressive compile-time automation and optimization—so much so that their previous tagline was actually "the magical disappearing UI framework" (literally!).&lt;/p&gt;

&lt;p&gt;This is true enough even today, where the compiler strips away a lot of the inner mechanisms of the framework.&lt;sup id="fnref1"&gt;1&lt;/sup&gt; Behind this philosophy, Svelte's creator &lt;a href="https://github.com/Rich-Harris" rel="noopener noreferrer"&gt;Rich Harris&lt;/a&gt; believes that &lt;em&gt;if the framework can analyze it anyway, then the developer should not worry about it&lt;/em&gt;—which subtly takes a stab at the more mainstream UI frameworks that do the work of state analysis and resolution at runtime instead. Such is the philosophy of &lt;em&gt;cybernetically enhanced web apps&lt;/em&gt;: let the tooling do the work!&lt;/p&gt;

&lt;p&gt;But how far does Svelte take this philosophy? Does Svelte go as far as to become a zero-cost abstraction?&lt;sup id="fnref2"&gt;2&lt;/sup&gt; Putting aside all of the fancy compile-time machinery, how is the developer experience even like? In this article, we review the merits of the Svelte framework and its wider ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stellar Documentation
&lt;/h2&gt;

&lt;p&gt;As with most things in life, first impressions also matter in the tech world. Poor examples, lengthy guides, inconvenient prerequisites, and strange syntax can easily turn off the most enthusiastic learners. As such, the classic Getting Started guide is where frameworks put their best foot forward.&lt;/p&gt;

&lt;p&gt;In flying colors, Svelte &lt;em&gt;really&lt;/em&gt; did put their best foot forward. The framework provides the following essential resources for onboarding:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Title&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://svelte.dev/docs" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The official documentation/reference for the Svelte framework proper.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://kit.svelte.dev/docs" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The official documentation/reference for the SvelteKit meta-framework.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://svelte.dev/examples" rel="noopener noreferrer"&gt;Examples&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;A repository of examples that serves as a tour of Svelte's features.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://svelte.dev/repl" rel="noopener noreferrer"&gt;REPL&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;A live REPL editor/playground for trying out ideas in Svelte.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://learn.svelte.dev/" rel="noopener noreferrer"&gt;Tutorial&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;An interactive tutorial that features a comprehensive guide alongside a live editing environment.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Needless to say, Svelte does not lack in documentation. The guides are comprehensive enough to be complete, yet concise and straight to the point. Furthermore, the tone and language are sufficiently technical, but not so much as to come off dry and full of jargon.&lt;/p&gt;

&lt;p&gt;The best examples come from the &lt;a href="https://learn.svelte.dev/" rel="noopener noreferrer"&gt;interactive tutorial&lt;/a&gt;, where the guides walk the reader through a motivating example before introducing features. The tutorial thus feels like a &lt;em&gt;journey&lt;/em&gt; of discovering the essence of Svelte rather than a &lt;em&gt;lecture&lt;/em&gt; on Svelte.&lt;/p&gt;

&lt;p&gt;Meanwhile, for quick experimentation, the live examples and the REPL are the easiest ways to test the framework's behaviors. In my experience, I've found the REPL to be an invaluable tool in my belt when prototyping stateful components. The REPL also doubles as my go-to resource for demonstrating Svelte's coolest features to my peers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Low Barrier to Entry
&lt;/h2&gt;

&lt;p&gt;Personally, the best part about Svelte is its low barrier to entry. Much like the approach of &lt;a href="https://www.typescriptlang.org/" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt; and &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt;, the Svelte language&lt;sup id="fnref3"&gt;3&lt;/sup&gt; strives to be a superset of the familiar trifecta of web development: HTML, CSS, and JavaScript.&lt;/p&gt;

&lt;p&gt;As a mentor to many of my peers, it is so natural to transition to Svelte right after a discussion on fundamental web features and APIs. That is to say, Svelte &lt;em&gt;truly&lt;/em&gt; feels more like an &lt;em&gt;extension&lt;/em&gt; of the web platform than a replacement. All the Web APIs and the DOM APIs are the same. There is no need to learn about replacements for the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tag and whatnot. Background knowledge just transfers so seamlessly.&lt;/p&gt;

&lt;p&gt;The language design of Svelte empowers beginners to prove to themselves that there is little to no magic behind UI frameworks; that everything is just built on top of the core Web APIs; and that everything is just plain old HTML, CSS, and JavaScript at the end of the day. The mental model perfectly bridges the gap between the world of components and the realities of the web platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  SvelteKit: The Ultimate SSR, CSR, and SSG Solution
&lt;/h2&gt;

&lt;p&gt;Before we proceed, let's begin by defining some terms:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Server-Side Rendering (SSR)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The web server dynamically generates new (templated) HTML on-the-fly based on certain variables from the server, the database, the request, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side Rendering (CSR)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The web server sends an empty HTML app shell to the browser.&lt;/li&gt;
&lt;li&gt;The browser executes the JavaScript to populate the UI.&lt;sup id="fnref4"&gt;4&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;This &lt;em&gt;usually&lt;/em&gt; implies extra round-trips to the server to fetch application data (typically in JSON).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Site Generation (SSG)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The build system precompiles&lt;sup id="fnref5"&gt;5&lt;/sup&gt; the HTML ahead of time.&lt;/li&gt;
&lt;li&gt;The web server thus only hosts static assets (e.g., HTML, CSS, and JS).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For many decades, the Web went back and forth between these three strategies—one trend after the next but never settling. To be fair, each has their own merits and trade-offs (as with most things in engineering).&lt;/p&gt;

&lt;p&gt;However, what's most impressive about the Svelte ecosystem is its ability to seamlessly mix and match these strategies. This is where &lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt; enters the picture.&lt;/p&gt;

&lt;p&gt;Powered by &lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;, SvelteKit is an officially maintained &lt;em&gt;meta-framework&lt;/em&gt;&lt;sup id="fnref5"&gt;5&lt;/sup&gt; that provides a full routing solution (client-side and server-side) on top of the Svelte framework proper. It combines the best of all worlds by empowering the developer to granularly choose which routes to render on the server (SSR), which routes to hydrate only on the client (CSR), and which routes to &lt;a href="https://kit.svelte.dev/docs/glossary#prerendering" rel="noopener noreferrer"&gt;prerender&lt;/a&gt; as static HTML (SSG).&lt;/p&gt;

&lt;p&gt;This seemingly zero-cost&lt;sup id="fnref2"&gt;2&lt;/sup&gt; flexibility is a godsend for pedants such as myself who take pride in squeezing every last byte of efficiency in the network.&lt;sup id="fnref6"&gt;6&lt;/sup&gt; This is a far cry from the olden days when we were often forced to commit to only one strategy per application—lest we "eject" from prescribed project structures and implement the magic ourselves.&lt;/p&gt;

&lt;p&gt;For example, consider a &lt;a href="https://php.net/" rel="noopener noreferrer"&gt;PHP&lt;/a&gt; app or an &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; app with &lt;a href="https://ejs.co/" rel="noopener noreferrer"&gt;EJS&lt;/a&gt; templating just for the sake of SSR. Also consider the trendy React apps from the pre-2016 era just for the sake of CSR. Or pehaps consider a Gatsby setup just for the sake of SSG.&lt;/p&gt;

&lt;p&gt;In all cases, we often required that these be separate applications. Back then, we just didn't have a holistic solution/framework that streamlines the notion of hybrid rendering strategies at the granularity level of routes. &lt;strong&gt;Now we do.&lt;sup id="fnref7"&gt;7&lt;/sup&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In other words, SvelteKit empowers us to ask &lt;em&gt;not&lt;/em&gt; whether we should commit to SSR &lt;a href="https://en.wikipedia.org/wiki/Exclusive_or" rel="noopener noreferrer"&gt;exclusive-or&lt;/a&gt; CSR &lt;a href="https://en.wikipedia.org/wiki/Exclusive_or" rel="noopener noreferrer"&gt;exclusive-or&lt;/a&gt; SSG, but to instead ask which specific routes we can use SSR &lt;a href="https://en.wikipedia.org/wiki/Inclusive_or" rel="noopener noreferrer"&gt;inclusive-or&lt;/a&gt; CSR &lt;a href="https://en.wikipedia.org/wiki/Inclusive_or" rel="noopener noreferrer"&gt;inclusive-or&lt;/a&gt; SSG on. It is a truly liberating experience to have everything just work™ out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility as a First-Class Citizen
&lt;/h2&gt;

&lt;p&gt;One feature that is especially admirable about Svelte is its treatment of accessibility as a &lt;a href="https://svelte.dev/docs/accessibility-warnings" rel="noopener noreferrer"&gt;first-class citizen&lt;/a&gt;. The Svelte compiler goes as far as to enforce accessibility best practices and warn against the anti-patterns.&lt;/p&gt;

&lt;p&gt;The interminable yellow squiggly lines may seem cumbersome at first, but one must always keep in mind that disabling them misses the entire point!&lt;/p&gt;

&lt;p&gt;Some posit that this is one of Svelte's most annoying features. I personally disagree. As someone who is not so well versed in the intricacies of accessibility, I greatly appreciate the automated reminders to get off my high horse of privilege and immerse myself into the viewpoint of disabled folks.&lt;/p&gt;

&lt;p&gt;However, I must admit that &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation" rel="noopener noreferrer"&gt;event delegation patterns&lt;/a&gt; in Svelte are a little cumbersome. Event delegation usually involves attaching event listeners to non-visible parent containers, which the compiler flags as accessibility warnings.&lt;/p&gt;

&lt;p&gt;Indeed, it is rather strange to attach a &lt;code&gt;click&lt;/code&gt; listener on seemingly arbitrary &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tags—even stranger when they're nested! Typically, these warnings are resolved by applying the correct ARIA roles and attaching the corresponding &lt;code&gt;keydown&lt;/code&gt; listeners. In these rare false positive cases, however, I am not totally against disabling the &lt;em&gt;particular&lt;/em&gt; warning altogether.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small Ecosystem
&lt;/h2&gt;

&lt;p&gt;Yes, the Svelte ecosystem is relatively small especially when compared to that of React. At face value, this is a bad look on the ecosystem. One may even dare to say: &lt;em&gt;"Svelte is dead!"&lt;/em&gt; But I believe there is a more satisfying reason behind the small ecosystem—there is just no need for a big one!&lt;/p&gt;

&lt;p&gt;Recall that the Svelte language aims to be an &lt;em&gt;extension&lt;/em&gt; of the web platform. As such, much of the framework internals use and accept (as arguments) the standard objects from Web APIs that are already built into browsers.&lt;/p&gt;

&lt;p&gt;Consider for example &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/fetch" rel="noopener noreferrer"&gt;&lt;code&gt;fetch&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Request" rel="noopener noreferrer"&gt;&lt;code&gt;Request&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Response" rel="noopener noreferrer"&gt;&lt;code&gt;Response&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData" rel="noopener noreferrer"&gt;&lt;code&gt;FormData&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Node" rel="noopener noreferrer"&gt;&lt;code&gt;Node&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent" rel="noopener noreferrer"&gt;&lt;code&gt;CustomEvent&lt;/code&gt;&lt;/a&gt;, etc. When most of the essentials are already built into browsers, it is rarely the case that a Svelte developer reaches out for libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy Integration with Web-First Libraries
&lt;/h3&gt;

&lt;p&gt;This is especially true when integrating with established third-party libraries (that were built for the Web rather than for a particular framework). One example that I can cite from experience is the &lt;a href="https://www.chartjs.org/" rel="noopener noreferrer"&gt;Chart.js&lt;/a&gt; library, which works with plain old &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement" rel="noopener noreferrer"&gt;&lt;code&gt;HTMLCanvasElement&lt;/code&gt;&lt;/a&gt; objects. In Svelte, a simple &lt;a href="https://svelte.dev/docs/element-directives#bind-this" rel="noopener noreferrer"&gt;&lt;code&gt;bind:this&lt;/code&gt;&lt;/a&gt; is &lt;em&gt;sufficient&lt;/em&gt; to set things in motion without much ceremony.&lt;sup id="fnref8"&gt;8&lt;/sup&gt; Of course, one may also opt to use wrapper libraries&lt;sup id="fnref9"&gt;9&lt;/sup&gt; for convenience.&lt;/p&gt;

&lt;p&gt;Nevertheless, the central point is that in the Svelte world, wrapper libraries are mainly for convenience. They are &lt;em&gt;sufficient&lt;/em&gt; to get the job done, but not &lt;em&gt;necessary&lt;/em&gt; as it is in other frameworks.&lt;sup id="fnref10"&gt;10&lt;/sup&gt; It's rare for a third-party library to &lt;em&gt;require&lt;/em&gt; some additional &lt;code&gt;svelte-adapter-*&lt;/code&gt; package just to cleanly interface with Svelte's reactivity.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Need for State Management Libraries
&lt;/h3&gt;

&lt;p&gt;Speaking of Svelte's reactivity, one more thing that is also worth mentioning is the fact that state management libraries are unheard of in the Svelte world. This is not because the "Svelte ecosystem is dead". Rather, to reiterate the point, the Svelte ecosystem does not need one!&lt;/p&gt;

&lt;p&gt;The built-in stores and reactive variables cover most (if not all) of the use cases. In fact, the reactive primitives and the &lt;a href="https://svelte.dev/docs/logic-blocks" rel="noopener noreferrer"&gt;logic blocks&lt;/a&gt; are so powerful together that they can elegantly express component-level state machines—zero third-party libraries required!&lt;/p&gt;

&lt;p&gt;On the off chance that these reactive primitives aren't sufficient, then perhaps it is a sign to reconsider the architecture altogether. &lt;em&gt;There is always a better way to do things...&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fine-Grained Reactivity (Sometimes!)
&lt;/h2&gt;

&lt;p&gt;Thanks to the compiler, Svelte boasts a "magical[ly] disappearing UI framework" where reactivity and state dependencies are resolved and bound at compile-time. For most primitive variables (e.g., strings, numbers, Booleans, etc.), fine-grained reactivity is sufficient and works great out of the box. In fact, it is exactly this fine-grained reactivity that enables Svelte to consistently &lt;a href="https://krausest.github.io/js-framework-benchmark/" rel="noopener noreferrer"&gt;outperform&lt;/a&gt; all of the UI frameworks except a few. More on this later.&lt;/p&gt;

&lt;p&gt;At the component level, the &lt;em&gt;unit&lt;/em&gt; of reactivity is the variable while the &lt;em&gt;catalyst&lt;/em&gt; for reactivity is reassignment. Svelte will even prevent a DOM re-render if the newly assigned state is strictly equal to its previous value. Note that for objects and arrays, this check is done &lt;em&gt;recursively&lt;/em&gt; to reach that extra mile in fine-grained reactivity.&lt;/p&gt;

&lt;p&gt;Despite these guard conditions, however, an unfortunately common mistake with non-primitive variables (e.g., objects) introduces a subtle pessimization on reactive side effects (which execute before the re-render guard).&lt;/p&gt;

&lt;p&gt;Consider the example below where we have a &lt;code&gt;data&lt;/code&gt; object with two fields: &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;other&lt;/code&gt;. In the example, we will only modify &lt;code&gt;data.count&lt;/code&gt; whenever we click on a &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;. Meanwhile, the &lt;code&gt;data.other&lt;/code&gt; field will &lt;em&gt;always&lt;/em&gt; remain untouched.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Recall that _only_ the `count` will be modified.&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Intuitively, this side effect should run per increment.&lt;/span&gt;
    &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updated count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// With that said, will this side effect ever run?&lt;/span&gt;
    &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updated other&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;other&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Increment `data.count` per click. --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{increment}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Surprisingly, the side effect with &lt;code&gt;data.other&lt;/code&gt; will actually run! This goes back to the fact that &lt;em&gt;variables&lt;/em&gt; are the units of reactivity while &lt;em&gt;reassignment&lt;/em&gt; is the catalyst for reactivity. Since &lt;code&gt;data.count&lt;/code&gt; is inside the &lt;code&gt;data&lt;/code&gt; variable (as a whole), then all dependents on the &lt;code&gt;data&lt;/code&gt; object will also be notified of the change! The &lt;code&gt;data.other&lt;/code&gt; side effect executes simply because it just happens to implicitly reference the &lt;code&gt;data&lt;/code&gt; variable (as a whole).&lt;/p&gt;

&lt;p&gt;The fix is frustratingly simple: &lt;strong&gt;normalize the primitives!&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Same old `data` here.&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Now we "normalize" the object into its primitives.&lt;/span&gt;
    &lt;span class="c1"&gt;// Alternatively, we could have just separated the variables&lt;/span&gt;
    &lt;span class="c1"&gt;// to begin with rather than putting them in an object.&lt;/span&gt;
    &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;other&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Same click handler.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Now only this side effect will run.&lt;/span&gt;
    &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updated count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// This is unreachable code because we hold no references&lt;/span&gt;
    &lt;span class="c1"&gt;// to `data` nor to the normalized `count` variable.&lt;/span&gt;
    &lt;span class="nl"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;updated other&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;other&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Increment `count` per click. --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{increment}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;+&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Kevin Bridges (&lt;a class="mentioned-user" href="https://dev.to/kevinast"&gt;@kevinast&lt;/a&gt;) goes into great detail about this behavior in his article on exploring Svelte's reactivity. The main point is that Svelte lets us "fine tune the reactivity"—for better or worse...&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/kevinast" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F103655%2Ffc9970f6-276f-4cd7-a23e-2de91f9279c8.jpeg" alt="kevinast"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/kevinast/responsive-svelte-exploring-svelte-s-reactivity-5cen" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Responsive Svelte (exploring Svelte's reactivity)&lt;/h2&gt;
      &lt;h3&gt;Kevin Bridges ・ Jul 17 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#svelte&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#reactivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#javascript&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;There are more examples out there where Svelte is not as fine-grained as I first thought. To cite another example, the &lt;code&gt;{#each}&lt;/code&gt; block &lt;a href="https://svelte.dev/docs/logic-blocks#each" rel="noopener noreferrer"&gt;actually diffs&lt;/a&gt; by the provided key expression when the backing array gets modified. This should be an incredibly fast operation, but I was nevertheless disappointed to find out that there was no fancy compile-time machinery happening behind the scenes.&lt;/p&gt;

&lt;p&gt;Returning to the framework benchmarks, perhaps it is for this reason why &lt;a href="https://www.solidjs.com/" rel="noopener noreferrer"&gt;SolidJS&lt;/a&gt; consistently outperforms Svelte. Simply put, when it comes to non-primitive variables, &lt;a href="https://www.solidjs.com/docs/latest/api#stores" rel="noopener noreferrer"&gt;SolidJS stores&lt;/a&gt; (which are essentially just recursive &lt;a href="https://www.solidjs.com/guides/reactivity" rel="noopener noreferrer"&gt;signals&lt;/a&gt; with fine-grained mutation helpers) are more fine-grained than that of Svelte.&lt;/p&gt;

&lt;p&gt;Now if there was somehow a way to integrate (at compile-time!) the fine-grained reactivity of SolidJS signals with the expressiveness of the Svelte language, then that would be the most unstoppable framework ever! But &lt;em&gt;alas&lt;/em&gt;, we do not live in a perfect world... yet!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; On 20 September 2023, the Svelte team announced &lt;a href="https://svelte.dev/blog/runes" rel="noopener noreferrer"&gt;runes&lt;/a&gt; for Svelte 5. The signal-based rewrite of the framework internals implements &lt;em&gt;finer&lt;/em&gt;-grained SolidJS-like reactivity at compile-time! &lt;em&gt;Perhaps the perfect world is not so far after all...&lt;/em&gt; 🎉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Exotically Magical Dollar
&lt;/h2&gt;

&lt;p&gt;If there is one part of Svelte that is worth nitpicking, it is certainly the bold decision to change the semantics of a seldom-used JavaScript feature: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label" rel="noopener noreferrer"&gt;labels&lt;/a&gt;. The &lt;a href="https://svelte.dev/docs/svelte-components#script-3-$-marks-a-statement-as-reactive" rel="noopener noreferrer"&gt;&lt;code&gt;$&lt;/code&gt; syntax&lt;/a&gt; is simultaneously the most elegantly brilliant and also the most exotically magical feature of the Svelte language.&lt;/p&gt;

&lt;p&gt;In the beginning of this review, I emphasized that Svelte prides itself in proving that there is no magic behind UI frameworks. &lt;strong&gt;This is the only exception.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a JavaScript purist, it initially horrified me to see the &lt;code&gt;$&lt;/code&gt; everywhere. I could forgive (and even applaud) the &lt;code&gt;$:&lt;/code&gt; label syntax, but the &lt;a href="https://svelte.dev/docs/svelte-components#script-4-prefix-stores-with-$-to-access-their-values" rel="noopener noreferrer"&gt;store prefix&lt;/a&gt; (i.e., &lt;code&gt;$store&lt;/code&gt;) was where I drew the line.&lt;/p&gt;

&lt;p&gt;In the beginning, I frequently found myself forgetting to prefix my stores with &lt;code&gt;$&lt;/code&gt; before accessing its inner value. Admittedly, this was a rather frustrating experience, especially considering the fact that it felt too magical for me. I knew that it desugared into the more verbose &lt;code&gt;subscribe&lt;/code&gt; pattern, but my inner purist self could not help but feel icky about the non-standard semantics. I eventually grew to embrace the syntax, but the journey was nevertheless jarring.&lt;/p&gt;

&lt;p&gt;Whenever I teach Svelte to JavaScript beginners, I always made sure to emphasize that the &lt;code&gt;$&lt;/code&gt; syntax is a non-standard Svelte-specific feature. As a mentor, the obligatory disclaimer that prefaces all of the lectures eventually does get old. But &lt;em&gt;alas&lt;/em&gt;, the incessant reminders are necessary—lest we fall into the trap of becoming Svelte developers (exclusively) rather than JavaScript developers.&lt;sup id="fnref11"&gt;11&lt;/sup&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Masterclass on Empowerment
&lt;/h2&gt;

&lt;p&gt;For all of my major projects, Svelte has become my go-to framework. In all of my years of experience in full-stack development, &lt;strong&gt;no other framework comes this close to perfection&lt;/strong&gt; (for now!). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Onboarding has a low barrier to entry (i.e., HTML, CSS, and JS are the only prerequisites).&lt;/li&gt;
&lt;li&gt;Outstanding documentation and interactive playgrounds.&lt;/li&gt;
&lt;li&gt;Minimal framework magic (aside from the aforementioned &lt;code&gt;$&lt;/code&gt; syntax).&lt;/li&gt;
&lt;li&gt;Minimal performance overhead (aside from the aforementioned "not-granular-enough" footguns) if any.&lt;/li&gt;
&lt;li&gt;Beautifully intuitive syntax and semantics behind the template language.&lt;/li&gt;
&lt;li&gt;Keeps the spirit of zero-cost&lt;sup id="fnref2"&gt;2&lt;/sup&gt; abstractions (or otherwise minimal overhead) alive.&lt;/li&gt;
&lt;li&gt;Maximal route-level flexibility in rendering strategies (with SvelteKit).&lt;/li&gt;
&lt;li&gt;Streamlined developer workflow and plugin system (thanks to Vite).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these reasons are why I &lt;em&gt;never&lt;/em&gt; hesitate to advocate for Svelte at my department. I have personally led several successful Svelte projects in the past semester alone. Many of these projects, in fact, involved onboarding complete beginners and experienced developers alike. Regardless of the team composition, Svelte never failed to produce successful projects. The same is true even for other teams that I have offered technical consultation on.&lt;sup id="fnref12"&gt;12&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The astute reader may notice a common theme in this review: &lt;strong&gt;empowerment&lt;/strong&gt;. Svelte and its zero-cost&lt;sup id="fnref2"&gt;2&lt;/sup&gt; philosophy empower teams to move fast with ease and confidence.&lt;/p&gt;

&lt;p&gt;Because Svelte does not require a degree in rocket science to understand, it also empowers individuals to believe that they &lt;em&gt;are&lt;/em&gt; capable of building full-stack applications; that front-end development can be intuitive; that back-end development doesn't have to be so scary; and that they are more qualified than they initially thought.&lt;sup id="fnref13"&gt;13&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This is why Svelte is a masterclass on empowerment.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Needless to say, I am a &lt;strong&gt;huge&lt;/strong&gt; fan of the &lt;a href="https://github.com/sveltejs" rel="noopener noreferrer"&gt;Svelte team&lt;/a&gt;'s work. I would like to thank them for empowering developers, keeping the spirit of innovation alive, and pushing the boundaries of full-stack web development.&lt;/em&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Aside from the necessities, of course! Namely: hydration code, client-side routing, and effect scheduling. Note that these are actually optional if one decides to fully &lt;a href="https://kit.svelte.dev/docs/glossary#prerendering" rel="noopener noreferrer"&gt;prerender&lt;/a&gt; their pages (i.e., static site generation). ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;I mean "zero-cost" in a C++ sense that framework features are compiled and packaged into the final bundle &lt;em&gt;if and only if&lt;/em&gt; they are actually used. Furthermore, the features that &lt;em&gt;are&lt;/em&gt; compiled and packaged cannot possibly be written by hand any better. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Yes, &lt;a href="https://gist.github.com/Rich-Harris/0f910048478c2a6505d1c32185b61934" rel="noopener noreferrer"&gt;Svelte is a language&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;In Svelte parlance, this is called &lt;a href="https://kit.svelte.dev/docs/glossary#hydration" rel="noopener noreferrer"&gt;hydration&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;In Svelte parlance, this is called &lt;a href="https://kit.svelte.dev/docs/glossary#prerendering" rel="noopener noreferrer"&gt;prerendering&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;Perhaps not exactly &lt;em&gt;zero-cost&lt;/em&gt; in the sense that SvelteKit's SSR capabilities require (the overhead of) a Node.js-compatible JavaScript runtime rather than an external web server base layer written in Rust or Go for example. There are ways to work around this, of course, but that is beyond the scope of this article. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn7"&gt;
&lt;p&gt;Note that nowadays, SvelteKit is &lt;em&gt;not&lt;/em&gt; the only framework that supports this level of flexibility. But then again, that is beyond the scope of this article. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn8"&gt;
&lt;p&gt;Yes, I'm aware that this is also possible in React with &lt;a href="https://react.dev/reference/react/useRef#manipulating-the-dom-with-a-ref" rel="noopener noreferrer"&gt;&lt;code&gt;useRef&lt;/code&gt;&lt;/a&gt;, but that is not our topic for today. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn9"&gt;
&lt;p&gt;The &lt;a href="https://www.npmjs.com/package/svelte-chartjs" rel="noopener noreferrer"&gt;&lt;code&gt;svelte-chartjs&lt;/code&gt;&lt;/a&gt; library seems to be a popular option among Svelte developers. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn10"&gt;
&lt;p&gt;By "necessary", I mean that it is otherwise unwieldly to write the integration ourselves. That is, it is "unwieldly" in the sense that we have to consider so many footguns just to get it right: two-way data bindings, re-renders, caching, performance, etc. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn11"&gt;
&lt;p&gt;Such is the trap that many beginners fall into when they eagerly jump into &lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt; before learning the fundamentals of JavaScript first. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn12"&gt;
&lt;p&gt;Some teams built CSR Svelte apps on Electron. Others went for the traditional hybrid SSR and CSR route. On some of my projects, SvelteKit has become my go-to solution for SSG. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn13"&gt;
&lt;p&gt;In fact, one of my friends even went from zero full-stack knowledge to AWS-certified cloud practitioner in three months after recommending Svelte to them! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>svelte</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>Please don't write confusing conditionals</title>
      <dc:creator>Basti Ortiz</dc:creator>
      <pubDate>Wed, 12 Jul 2023 14:41:30 +0000</pubDate>
      <link>https://dev.to/somedood/please-dont-write-confusing-conditionals-2n32</link>
      <guid>https://dev.to/somedood/please-dont-write-confusing-conditionals-2n32</guid>
      <description>&lt;p&gt;Have you ever spent more than a few seconds staring at the same line of code? How often did you find conditionals that were tricky to parse? In this article, we discuss how confusing conditionals manifest in our code. Along the way, we also explore different refactoring techniques for improving the readability of conditional control flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Double Negatives
&lt;/h2&gt;

&lt;p&gt;A double negative arises when we negate a variable whose name is already in a non-affirmative style. Consider the following example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Non-affirmative Naming Convention&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isNotReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isForbidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cannotJoinRoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasNoPermission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Negating once results in an awkward double negative situation.&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isNotReady&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isForbidden&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cannotJoinRoom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasNoPermission&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is opposed to the &lt;u&gt;&lt;strong&gt;affirmative style&lt;/strong&gt;&lt;/u&gt;, which requires less cognitive load to parse because one does not need to jump through the hoops of negating the variable name to extract the essence of its logic. In other words, the &lt;em&gt;intent&lt;/em&gt; behind an affirmative variable may be read as is—no hoops required! Consider the following modifications to the previous example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Affirmative Naming Convention&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAllowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canJoinRoom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hasPermission&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Negation actually makes sense here!&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isReady&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;canJoinRoom&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, non-affirmative naming conventions are sometimes inevitable due to standards and backwards-compatibility. Take the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/disabled" rel="noopener noreferrer"&gt;&lt;code&gt;HTMLInputElement#disabled&lt;/code&gt;&lt;/a&gt; property of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API" rel="noopener noreferrer"&gt;HTML DOM APIs&lt;/a&gt; for example. The presence of the &lt;code&gt;disabled&lt;/code&gt; attribute in an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; tag tells the browser to (visually and literally) disable the element's form controls. Otherwise, its absence causes the &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; to exhibit its default behavior, which is to accept user input. This is an unfortunate side effect of the ergonomics of HTML.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Normal Checkbox (Default) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Disabled Checkbox --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nevertheless, we should still strive for affirmative naming conventions wherever possible. They are easier to read and parse simply because there is no need to mentally negate the variable name at all times. This rule applies to both variables names and function names alike.&lt;/p&gt;

&lt;h2&gt;
  
  
  Non-affirmative Control Flows
&lt;/h2&gt;

&lt;p&gt;The next form of a double negative is a little bit more subtle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Suppose that we _do_ follow affirmative naming conventions.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAllowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;checkSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// There is something funny about this...&lt;/span&gt;
    &lt;span class="nf"&gt;doError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Notice how the `else` block is practically a double negation?&lt;/span&gt;
    &lt;span class="nf"&gt;doSuccess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As seen above, the non-affirmative style can also pervade conditional control flow. Recall that an &lt;code&gt;else&lt;/code&gt; block is practically a negation of the corresponding &lt;code&gt;if&lt;/code&gt; condition. We must therefore extend the affirmative style here. The fix is actually rather simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Just invert the logic!&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isAllowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;checkSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSuccess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same rule applies to equality and inequality checks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Don't do this!&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSuccess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Prefer this instead.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSuccess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some may even go as far as to let a conditional block be blank just to negate a condition in affirmative style. Although I am not advocating for everyone to take it this far, I can see why this may be more readable for some people. Take the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof" rel="noopener noreferrer"&gt;&lt;code&gt;instanceof&lt;/code&gt;&lt;/a&gt; operator for example, which cannot be easily negated without parentheses.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Intentionally left blank.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Do actual work here (in the negation).&lt;/span&gt;
    &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exceptions for Early Returns
&lt;/h3&gt;

&lt;p&gt;As a quick aside, there are special exceptions for conditional control flows that return early. In such cases, the negation &lt;em&gt;may&lt;/em&gt; be necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Return early here.&lt;/span&gt;
    &lt;span class="nf"&gt;doError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Otherwise, proceed with the success branch.&lt;/span&gt;
&lt;span class="nf"&gt;doSuccess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wherever possible, though, we should still attempt to invert the logic if it results in lesser nesting, fewer levels of indentation, and more readable affirmative styles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Prefer affirmative early returns.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSuccess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// If we did not invert the logic, this would have been&lt;/span&gt;
&lt;span class="c1"&gt;// nested inside the `!isAllowed` conditional block.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doPermissionError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// When all else fails, do something else.&lt;/span&gt;
&lt;span class="nf"&gt;doSomethingElse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another way to express the same control flow in an affirmative style (without early returns) is as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Hooray for the affirmative style!&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isAllowed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSuccess&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hasPermission&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSomethingElse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doPermissionError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, there are plenty of other ways to swap, invert, and refactor the code—the merits for each are totally subjective. Preserving the affirmative conventions thus becomes some kind of an art form. In any case, code readability will always improve as long as we uphold the general guidelines of the affirmative style.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compound Conditions
&lt;/h2&gt;

&lt;p&gt;The story gets a little bit more complicated with logical operators such as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND" rel="noopener noreferrer"&gt;&lt;code&gt;AND&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR" rel="noopener noreferrer"&gt;&lt;code&gt;OR&lt;/code&gt;&lt;/a&gt;. For instance, how do we refactor the code below in a more affirmative style?&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This is fine... but there has to be a better way,&lt;/span&gt;
&lt;span class="c1"&gt;// right? There are just too many negations here!&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isGuest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doAnotherThing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For compound conditionals, we introduce the most underrated law of Boolean algebra: &lt;a href="https://en.wikipedia.org/wiki/De_Morgan%27s_laws" rel="noopener noreferrer"&gt;De Morgan's Laws&lt;/a&gt;!&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Suppose that these are **any** two Boolean variables.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The following assertions will **always** hold for any&lt;/span&gt;
&lt;span class="c1"&gt;// possible pairing of values for `a` and `b`.&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to De Morgan's Laws, we now have a way to "distribute" the negation inside a condition and then "flip" its operator (from &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; to &lt;code&gt;||&lt;/code&gt; and vice-versa).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Although the following examples only feature binary comparison (i.e., two elements), De Morgan's Laws are generalizable over any number of conditional variables as long as we respect &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence" rel="noopener noreferrer"&gt;operator precedence&lt;/a&gt;. Namely, the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator is always evaluated first before the &lt;code&gt;||&lt;/code&gt; operator.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// By De Morgan's Laws, we can "factor out" the negation as follows.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isGuest&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doAnotherThing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Then we simply invert the logic as we did in the previous section.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isUser&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isGuest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doAnotherThing&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, isn't that &lt;em&gt;much&lt;/em&gt; more readable? Using De Morgan's Laws, we can clean up conditionals that have "too many negations".&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The overall theme should be apparent at this point. Wherever possible, we should avoid writing code that forces the reader to jump through hoops that (needlessly) necessitate extra cognitive overhead. In this article, we discussed the following techniques:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Encourage affirmative naming conventions.

&lt;ul&gt;
&lt;li&gt;Avoid negative terms/prefixes like &lt;code&gt;no&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;, &lt;code&gt;dis-&lt;/code&gt;, &lt;code&gt;mal-&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Prefer the positive equivalents.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Invert conditional control flow (where possible) to accommodate for the affirmative style.

&lt;ul&gt;
&lt;li&gt;Feel free to play around when swapping, inverting, and refactoring branches.&lt;/li&gt;
&lt;li&gt;Early returns &lt;em&gt;may&lt;/em&gt; necessitate negations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use some tricks from Boolean algebra to invert condtionals.

&lt;ul&gt;
&lt;li&gt;De Morgan's Laws are especially powerful tools for refactoring!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Now go forth and bless the world with cleaner conditionals!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tips</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
