<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Reverse Pitch]]></title><description><![CDATA[The pitch you'll hear vs. the reality you'll build. Weekly notes on software engineering, cloud infrastructure and AI.]]></description><link>https://www.reversepitch.io</link><image><url>https://substackcdn.com/image/fetch/$s_!5Kya!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4624a9d4-8af5-4f86-a5c6-e6f3a294e61d_256x256.png</url><title>Reverse Pitch</title><link>https://www.reversepitch.io</link></image><generator>Substack</generator><lastBuildDate>Fri, 23 Oct 2026 09:38:36 GMT</lastBuildDate><atom:link href="https://www.reversepitch.io/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Yuyi Pacheco Kimura]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[reversepitch@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[reversepitch@substack.com]]></itunes:email><itunes:name><![CDATA[Yuyi Kimura]]></itunes:name></itunes:owner><itunes:author><![CDATA[Yuyi Kimura]]></itunes:author><googleplay:owner><![CDATA[reversepitch@substack.com]]></googleplay:owner><googleplay:email><![CDATA[reversepitch@substack.com]]></googleplay:email><googleplay:author><![CDATA[Yuyi Kimura]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Sandboxing your Coding Agents]]></title><description><![CDATA[You can't fully control what an agent decides to do. You can control what it's able to reach when it decides.]]></description><link>https://www.reversepitch.io/p/sandboxing-your-coding-agents</link><guid isPermaLink="false">https://www.reversepitch.io/p/sandboxing-your-coding-agents</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Mon, 05 Oct 2026 21:43:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!0aWk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0aWk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0aWk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0aWk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0aWk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0aWk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0aWk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg" width="1024" height="506" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:506,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64464,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.reversepitch.io/i/219007245?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0aWk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0aWk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0aWk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0aWk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c7f57fb-e7aa-4937-a00b-e4e64b364495_1024x506.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Don&#8217;t let your AI go rogue</figcaption></figure></div><p>Recently, our GitHub Actions workflows stopped running. No failed builds, no red checks, just nothing. Deployments were halted until we found the root cause, and it turned out to be GitHub Copilot. An engineer asked it to perform a task, and somewhere along the way it decided the right move was to disable every workflow in the repository.</p><p>Nothing in production went down, but it stuck with me. The agent wasn&#8217;t being malicious. It was doing what agents do: pushing toward the goal it was given, even when the path there goes through something nobody would have approved.</p><blockquote><p>You can&#8217;t fully control what an agent decides to do. You can control what it&#8217;s able to reach when it decides.</p></blockquote><p>Since then I&#8217;ve been testing the options Claude Code offers to sandbox an agent. There are three levels, each one draws the boundary in a different place, and each one fits a different way of working.</p><h2>Level 1: Sandboxing the Bash tool</h2><p>The first level is an OS-enforced boundary around the shell commands Claude runs on your machine. You define which paths those commands can read or write, and which domains they can reach through an allowlist. You can also block commands you consider too dangerous for an agent to run at all.</p><p>You turn it on by running <code>/sandbox</code>. Project-level settings live in <code>.claude/settings.local.json</code>, and if you want every project sandboxed, you define it in <code>~/.claude/settings.json</code>.</p><p>The tricky part is choosing the boundaries, because they depend on the work you&#8217;re doing in that project. If it&#8217;s a Python project and the agent should be able to install dependencies, you need <code>pypi.org</code> and <code>files.pythonhosted.org</code> in the allowlist. If the application talks to S3, the agent will need <code>*.amazonaws.com</code>. Too tight and the agent can&#8217;t work. Too loose and the sandbox is decoration.</p><p><strong>The gotcha.</strong></p><p>While testing this, I found that the agent can request access to a specific domain for a specific command. It sounds harmless, and it&#8217;s more dangerous than it looks. Once a sandbox is in place, it&#8217;s tempting to relax and let <code>auto</code> mode handle approvals. But if the agent can ask for a domain and <code>auto</code> mode approves it, your network constraints get bypassed without you ever noticing.</p><p>There&#8217;s a second escape route in the same spirit. When a command fails under the sandbox, Claude can offer to retry it outside the sandbox entirely. Approve that once without reading carefully and the command runs with your full access, network and filesystem included.</p><p>The fix is two flags in your global config:</p><pre><code><code>{
  "sandbox": {
    "allowUnsandboxedCommands": false,
    "network": {
      "strictAllowlist": true
    }
  }
}
</code></code></pre><p><code>strictAllowlist</code> makes Claude Code refuse those per-command domain requests, so the allowlist you wrote is the allowlist you get. <code>allowUnsandboxedCommands</code> set to <code>false</code> removes the unsandboxed retry, so when a command fails inside the sandbox, it stays failed and you decide what happens next.</p><h2>Level 2: Sandboxing the whole runtime</h2><p>The Bash sandbox has a blind spot: it only covers shell commands. Tools like Read, Edit and WebFetch run outside of it, and more importantly, so do your MCP servers and hooks, with your full access. The runtime sandbox closes that gap by putting the entire Claude Code process inside the boundary. Every tool, server and hook inherits the same filesystem and network limits.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tYnD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tYnD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 424w, https://substackcdn.com/image/fetch/$s_!tYnD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 848w, https://substackcdn.com/image/fetch/$s_!tYnD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 1272w, https://substackcdn.com/image/fetch/$s_!tYnD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!tYnD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png" width="1456" height="621" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:621,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:203777,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.reversepitch.io/i/219007245?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tYnD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 424w, https://substackcdn.com/image/fetch/$s_!tYnD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 848w, https://substackcdn.com/image/fetch/$s_!tYnD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 1272w, https://substackcdn.com/image/fetch/$s_!tYnD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa230fe11-4a09-4960-96a4-a7ec2290923c_1568x669.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It takes a few more pieces to set up. On Linux you need <code>bubblewrap</code> and <code>socat</code>, while macOS relies on the built-in Seatbelt. On top of that, you need the Node.js package <code>@anthropic-ai/sandbox-runtime</code>, which gives you the <code>srt</code> command.</p><p>By default, <code>srt</code> reads its configuration from <code>~/.srt-settings.json</code>, and you can point it to a different file with <code>--settings</code>. A starter configuration that allows GitHub, PyPI and npm looks like this:</p><pre><code><code>{
  "network": {
    "allowedDomains": [
      "api.anthropic.com", "claude.ai", "platform.claude.com",
      "github.com", "*.github.com",
      "pypi.org", "files.pythonhosted.org", "registry.npmjs.org"
    ],
    "deniedDomains": []
  },
  "filesystem": {
    "denyRead": ["~/.ssh", "~/.aws"],
    "allowWrite": [".", "~/.claude", "~/.claude.json", "/tmp"],
    "denyWrite": [
      "~/.claude/settings.json", "~/.claude/agents", "~/.claude/commands",
      ".claude/settings.json", ".claude/settings.local.json", ".env"
    ]
  }
}
</code></code></pre><p>The network section is the same idea as before. The filesystem section is where this level earns its place: your SSH keys and AWS credentials can&#8217;t be read, and the agent can&#8217;t rewrite its own settings, agents, commands or your <code>.env</code>. Since the whole process sits inside the boundary, that also holds for a hook or an MCP server trying to reach them.</p><p>Then you start your session with <code>srt claude</code>, or <code>srt --settings &lt;custom_path&gt; claude</code> if you&#8217;re using a custom configuration.</p><p>This is the minimum level at which Anthropic suggests considering <code>--dangerously-skip-permissions</code>, the flag that lets Claude Code handle unattended runs. I treat that as a hard line. Never use the flag on a Claude Code process with full access, and not with only the Bash sandbox either, because your MCP servers and hooks would still be running with everything you have.</p><h2>Level 3: Running inside a container</h2><p>A dev container runs Claude Code inside a Docker container that your editor attaches to. Your repo is bind-mounted, so edits show up on your host, but every command, MCP server and hook runs inside the container, with its own filesystem, OS user and tools.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FsuD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FsuD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 424w, https://substackcdn.com/image/fetch/$s_!FsuD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 848w, https://substackcdn.com/image/fetch/$s_!FsuD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 1272w, https://substackcdn.com/image/fetch/$s_!FsuD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 1456w" sizes="auto, 100vw"><img src="https://substackcdn.com/image/fetch/$s_!FsuD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png" width="1456" height="713" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/edb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:713,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:159378,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.reversepitch.io/i/219007245?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FsuD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 424w, https://substackcdn.com/image/fetch/$s_!FsuD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 848w, https://substackcdn.com/image/fetch/$s_!FsuD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 1272w, https://substackcdn.com/image/fetch/$s_!FsuD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb027ce-257a-499e-abb3-de0713ec8c9e_2280x1116.png 1456w" sizes="auto, 100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Choosing between this and <code>srt</code> comes down to a few things:</p><ul><li><p><strong>Pick a container when</strong> you want your home directory and credentials invisible by default, a reproducible toolchain the whole team shares, or a boundary for unattended <code>--dangerously-skip-permissions</code> runs.</p></li><li><p><strong>Pick </strong><code>srt</code><strong> when</strong> you can&#8217;t run Docker, or you want isolation with zero image maintenance.</p></li><li><p><strong>Pick neither for untrusted repos.</strong> Containers share the host kernel, and the docs say to use them only with trusted repositories. For untrusted code, use a VM or a cloud session.</p></li></ul><p>You can run it with a container runtime like Docker directly, or headless with the Dev Container CLI. The Dev Container route is the easier one to set up, so that&#8217;s the one I&#8217;ll show.</p><p>Start with a minimal <code>.devcontainer/devcontainer.json</code>:</p><pre><code><code>{
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "features": {
    "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
  }
}
</code></code></pre><p>This adds Claude Code to the base image and nothing else. You get filesystem isolation, but the network is left wide open. Anthropic provides hardened references <a href="https://github.com/anthropics/claude-code/tree/main/.devcontainer">here</a>, including the <code>Dockerfile</code> you&#8217;d use to build the image.</p><p>What I like most about this option is how shareable it is. You build a single image with all the tooling your projects need and all the agent configuration, and every engineer on the team runs the same thing.</p><p><strong>Credentials are the real win.</strong></p><p>Instead of Claude Code using your CLI tools with your account, which probably has more permissions than you&#8217;d ever give an agent, you provision the container with its own limited credentials. In most scenarios, an agent only needs read access to pull extra context about your infrastructure, your satellite services or your issue tracker. That alone drastically reduces the chance of data leaking, or of a rogue action happening as a side effect of the agent chasing its goal.</p><p>That&#8217;s the Copilot story all over again. Disabling workflows had nothing to do with the task, but the agent had the permission to do it, so it did.</p><h2>Matching the boundary to the work</h2><p>None of these levels is the right one for everything. The Bash sandbox is a good default when you&#8217;re at the keyboard and approving what the agent does, as long as both flags are set. The runtime sandbox is where I&#8217;d start the moment MCP servers, hooks or unattended runs get involved. The container is for when a team needs the same boundary everywhere, and when you want the agent working with credentials scoped to what it actually needs.</p><blockquote><p>An agent will take whatever path gets it to the goal. The sandbox decides which paths exist.</p></blockquote><p>If you&#8217;re running agents with full access today, start with <code>/sandbox</code> and those two flags. It&#8217;s a small change, and it&#8217;s the one I wish we&#8217;d had in place before our workflows went quiet.</p><div><hr></div><p><em>Reverse Pitch is one post a week on software engineering and the career around it, written from inside the work.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/p/sandboxing-your-coding-agents?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/p/sandboxing-your-coding-agents?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[What a Pokémon-Playing Bot Shows About Decision Models]]></title><description><![CDATA[A decision model is only as good as the options you hand it.]]></description><link>https://www.reversepitch.io/p/what-a-pokemon-playing-bot-shows</link><guid isPermaLink="false">https://www.reversepitch.io/p/what-a-pokemon-playing-bot-shows</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Mon, 28 Sep 2026 13:01:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!9Y_b!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9Y_b!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9Y_b!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Y_b!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Y_b!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Y_b!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9Y_b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg" width="1456" height="794" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:794,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3192013,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.reversepitch.io/i/217615196?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9Y_b!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 424w, https://substackcdn.com/image/fetch/$s_!9Y_b!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 848w, https://substackcdn.com/image/fetch/$s_!9Y_b!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!9Y_b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad0a0a71-821f-473b-8ff7-42c43558ab24_2816x1536.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Generated with Gemini</figcaption></figure></div><p>In the last few days, I&#8217;ve seen a lot of people using Jev, some of them claiming complete bullshit while others claiming more realistic gains. I tried Jev Playground and reviewed some projects to see how real developers are using it. I noticed a pattern: Jev isn&#8217;t the system. It&#8217;s one layer inside a much larger architecture.</p><p>One project that really stood out and demonstrates Jev&#8217;s ability to offer genuine value is Christian Mathiesen&#8217;s <strong><a href="https://github.com/christianmat/jev-pokemon">&#8220;Jev Plays Pok&#233;mon Red&#8221;</a></strong>. The headline reads, &#8220;Jev plays the game autonomously with no scripts or cheats&#8221; and it&#8217;s spot on, which is impressive. However, after diving into the codebase, I think the most important takeaway isn&#8217;t necessarily about Jev.</p><blockquote><p>Jev didn&#8217;t make the project possible on its own. The harness did, and Jev was the last piece of the puzzle.</p></blockquote><h2>What Jev is (and isn&#8217;t)?</h2><p>Jev is a decision model. You give it a state and a set of questions along with the structured output you expect from it, either choice, score, or true/false. It isn&#8217;t a chatbot and doesn&#8217;t generate text. One key takeaway is that it provides probability distributions.</p><p>Here is a simple example of how it looks like. You provide a state:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
  "state": {
    "battle": "Gym Leader Brock",
    "myPokemon": {
      "species": "SQUIRTLE",
      "level": 14,
      "hp": "28/40",
      "types": "WATER"
    },
    "enemy": {
      "species": "ONIX",
      "level": 14,
      "hp": "35/35",
      "types": "ROCK/GROUND"
    }
  }
}</code></pre></div><p>Then, you define the question you want Jev to answer and the criteria:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
  "decision": {
    "type": "choice",
    "instructions": "You are in a Pok&#233;mon battle. Choose the best action.",
    "criteria": {
      "Use TACKLE": "NORMAL move, power 35. Not very effective against ROCK/GROUND.",
      "Use BUBBLE": "WATER move, power 20. Super effective x4 against ROCK/GROUND.",
      "Use POTION": "Heal SQUIRTLE by up to 20 HP. Uses the turn."
    }
  }
}</code></pre></div><p>And Jev provide the following structured answer:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
  "answers": {
    "decision": {
      "type": "choice",
      "choice": "Use BUBBLE",
      "confidence": 0.99,
      "probabilities": {
        "Use BUBBLE": 0.99,
        "Use POTION": 0.01,
        "Use TACKLE": 0
      }
    }
  }
}</code></pre></div><p>It doesn&#8217;t see the screen, never presses a button and doesn&#8217;t remember your last request. Each call is fresh and stateless over the list of options you provide.</p><p>All these constraints, make Jev fast and cheap enough to run on every single decision while playing a video game like Pok&#233;mon Red. A continuous 24 hours of gameplay could cost $1~1.70. A frontier lab LLM like GPT-5.6 Terra could cost $60~110 while also being multiple times slower as well. That&#8217;s the edge a decision model provide.</p><h2>But how Jev actually play the game?</h2><p>That&#8217;s the most interesting thing from analyzing this project (and any other serious one about Jev). From around 4,400 lines of code, only 200 of them talk to Jev. It is specifically used for choosing a focus, define where to go (using grid like coordinates), choose battle action, picking an answer from a menu and spelling nickname.</p><p>Everything else, is a harness that directly read the Game Boy&#8217;s RAM in order to capture the map, your position, your party&#8217;s HP, bag, badges, story event flags and battle stats. The harness is capable of capturing all the information needed and structure it in a way the decision model can provide a legal/valid action to perform.</p><p>To me that&#8217;s amazing, especially because Jev&#8217;s decision are only as good as the information you provide to it. That&#8217;s why a great harness, a well structured architecture, a frontier lab model used to reasoning and finally Jev to make decisions, is the chain that makes emerging projects to be useful and not simply AI slop trying to hype any new thing that gets released.</p><h2>The layer Jev replaced</h2><p>While I definitely believe that Jev is one piece of the puzzle, its important to understand how the same scenario looks like without it.</p><p><strong>Write the decisions in code.</strong></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;typescript&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-typescript">if (hpFraction &lt; 0.25) goHeal();
else if (teamLevel &lt; objective.level - 5) goTrain();
else if (balls &gt; 0 &amp;&amp; party.length &lt; 6 &amp;&amp; isNewType(wild)) throwBall();
else if (bestMove.effectiveness &gt;= 2) useMove(bestMove);
...</code></pre></div><p>This works for about a day, then break miserably and require you to keep adjusting a blob of code that grows unbounded. Every new situation is a new branch, every branch interact with others and the rule tree becomes the project.</p><p><strong>Train a new model.</strong></p><p>When seeing Jev classification/extraction capabilities for the first time, I immediately related to custom trained models that were capable of doing similar tasks very fast and provide score as well. What separate Jev from this is its ability to generalize. NER and classifier models requires a labeled dataset and a training step in order to provide &#8220;decisions&#8221;. If new constraints or scenarios surface, more data and a new training must be done.</p><p>Its powerful, but slow and expansive. ML operations becomes the bottleneck.</p><p><strong>Use a frontier lab LLM.</strong></p><p>Provide the context and the structured output schema to the frontier lab and you get Jev&#8217;s equivalent output. The problem becomes latency and cost. These models are slow and too expensive to be used on every decision.</p><blockquote><p>A decision model closes the gap, and it&#8217;s a real one. Evaluating 100,000 scenarios with sub second latency while being cost effective is a real game-changer.</p><p>It simply isn&#8217;t the gap that hype posts and attention-seekers describe.</p></blockquote><h2>The core is around the decisions</h2><p>Jev Plays Pok&#233;mon Red is a great project, and it&#8217;s a good showcase of what a decision model makes cheap and scalable. A few years ago, getting this quality of in-game judgment across an entire RPG meant either a rule engine big enough to be a job on its own or a training pipeline. Here it&#8217;s five function calls.</p><p>But look at what those five calls sit on: RAM decoding, a ROM-derived world graph, counterfactual pathfinding, failure memory, milestone verification and deterministic execution. That&#8217;s the core. Jev removed the last blocker.</p><blockquote><p>Jev isn&#8217;t the next big thing. It&#8217;s what finally lets the systems you were already building make decisions well, quickly, and cheaply enough to scale.</p></blockquote><p>Make sure to review <a href="https://github.com/christianmat/jev-pokemon">Christian Mathiesen project</a>. I found it quite interesting and cool.</p><div><hr></div><p><em>Reverse Pitch is one post a week on software engineering and the career around it, written from inside the work.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Reverse Pitch on "Just Build Things"]]></title><description><![CDATA[For a decade, "it works" passed for competence. Then agents made it free.]]></description><link>https://www.reversepitch.io/p/the-reverse-pitch-on-just-build-things</link><guid isPermaLink="false">https://www.reversepitch.io/p/the-reverse-pitch-on-just-build-things</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Wed, 23 Sep 2026 12:30:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!CPPK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CPPK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CPPK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 424w, https://substackcdn.com/image/fetch/$s_!CPPK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 848w, https://substackcdn.com/image/fetch/$s_!CPPK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 1272w, https://substackcdn.com/image/fetch/$s_!CPPK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CPPK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png" width="1200" height="680" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:680,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:68607,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.reversepitch.io/i/215980842?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CPPK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 424w, https://substackcdn.com/image/fetch/$s_!CPPK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 848w, https://substackcdn.com/image/fetch/$s_!CPPK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 1272w, https://substackcdn.com/image/fetch/$s_!CPPK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09dd996c-01fd-43ff-b556-217ebbea58ec_1200x680.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>For about six years, the best career advice in software was &#8220;Just build things&#8221;. Skip the credential, skip the theory, ship something real and public, and the job follows. It got repeated often enough that it stopped sounding like advice and started sounding like a description of how the industry worked.</p><p>It was also, for most of that time, true.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/subscribe?"><span>Subscribe now</span></a></p><p></p><h2>The pitch</h2><p>Software was the one well-paid technical career with no major gate on it. You could enter from a bootcamp, from an unrelated career, from nothing but a laptop and a year of evenings. The portfolio was the credential. The deployed project was the proof.</p><p>And people did it. Large numbers of them, including people for whom no other door to that income existed. The anti-credential half of the argument was correct, too, which is the part critics skip: a computer science degree never guaranteed competence either. The pitch was reacting to something real, an industry gatekeeping on a proxy that did not predict much, and &#8220;show me what you built&#8221; was an improvement on it.</p><p>So the pitch was not a con. It was probably the widest door into well-paid technical work open in that decade, and the people who walked through it earned what they got.</p><p>What it was not was permanent.</p><h2>The reality</h2><p>What follows is my take, built out of what I have run into rather than out of any study. Fifteen or so engineers over five years, interviewed or worked alongside. Not a sample. Just what I saw, and why I think it happened.</p><p><strong>What I keep running into.</strong></p><p>Three of them, and none are the things people usually reach for when they complain about juniors.</p><p><strong>The ORM with nothing underneath it.</strong></p><p>The fair thing first: using an ORM is not a failure. That is what it is for, and people who insist on hand-writing every query are usually selling something.</p><p>The failure is not knowing what comes out the other side. I have worked with engineers who could not tell me what SQL a queryset produced and, more to the point, could not tell me what it would cost against two million rows instead of two hundred. Showing them the generated query moves the gap rather than closing it, because reading it requires knowing what an index actually does, and why a join on an unindexed column is a different animal from a join on a primary key.</p><p>The consequence is specific. You go blind to performance. Not bad at it. Blind to it. Every query looks the same from where you are standing, so you cannot tell the page that is fine from the page that is one traffic spike from falling over, and you find out which is which when the spike arrives.</p><p><strong>The page that was hidden and therefore secure.</strong></p><p>I have met engineers who believed that removing a link from the navigation, or conditionally hiding a button, prevented unauthorized access. The reasoning is internally consistent. The user cannot see it, so the user cannot reach it.</p><p>An attacker never touches your interface. They open the network tab, watch what your own frontend sends, learn the shape of your API in about twenty minutes, and make the requests directly. Your navigation is not part of that conversation. The failure is not a missing fact about authorization headers. It is a mental model in which the UI <em>is</em> the system rather than one client of it.</p><p><strong>The disabled CORS.</strong></p><p>This is the one I keep returning to, because it is not a gap in what tutorials teach. It is what tutorials teach.</p><p>Follow almost any &#8220;build your first API&#8221; walkthrough and you reach the point where the browser refuses the request, and the walkthrough tells you to allow all origins. It has to. Explaining the same-origin policy properly costs a page and a half and loses half the readers. So the instruction sits there unexplained, and it works, and everyone moves on.</p><p>I have worked with engineers who carried that line into production without ever learning what it did. Not people who weighed a risk and accepted it. People who did not know a policy existed, because the only context in which they had ever met it was as an obstacle that a copied line removed.</p><p>I have also met engineers who could not describe what happens between a browser and a server when a page loads, and one who had never used version control. I am not making scenes out of those. Past a point I am just listing things people did not know, and that is a meaner article than this one.</p><p><strong>What all three have in common.</strong></p><p>They worked.</p><p>CORS wide open, the page loads. The ORM query with no index behind it, the feature ships and the tests pass. The admin route hidden from the nav, the demo looks locked. Nobody got caught, because in every case the thing they built did what it was supposed to do.</p><p>That is the whole argument, so let me put it flatly: <strong>&#8220;it works&#8221; was accepted as proof of competence.</strong></p><p>For a long time that was defensible. If you got a functioning application in front of a user, you had absorbed a great deal on the way, because the path was strewn with things that would stop you. The artifact was expensive, so the artifact was evidence. The industry did not skip fundamentals out of laziness or greed. It substituted the artifact for the understanding, because the artifact was the cheapest reliable proxy anyone had.</p><p>There was nothing else to fall back on. Software has no licensing board, no accredited entry path, no articling period, no bar exam. When hiring volume grew faster than any shared idea of what a junior ought to know, the bar defaulted to the only thing every interviewer could evaluate: does the thing run.</p><p>Compare that to the careers software was outpaying. A civil engineer who has never poured concrete still understands loads and material limits well enough to take direction from a senior, and to notice when an instruction sounds wrong. A newly qualified lawyer who has never argued a case can still read one. Those professions gate on fundamentals before experience, deliberately, because experience takes years and fundamentals can be verified on a Tuesday. Software gated on the artifact instead, and paid more for it.</p><p><strong>Where I sat in this.</strong></p><p>I invested in fundamentals early, and that is most of why I stood out rather than anything more flattering. I also got paid off the same mispricing. My salary was above what a newly qualified lawyer in my country earned, and not because I was worth more than them. Saying the bar was too low means saying I was overpaid relative to my peers in other fields, and I was.</p><p><strong>What I got wrong.</strong></p><p>I assumed this was a bootcamp problem, and held that view confidently for years before the evidence stacked up against me. Two of the three engineers in those scenes had computer science degrees. The gap does not track which door someone came through. It tracks whether they went looking for the why while they were inside, and both doors will hand you a working result and let you leave without asking how it got there.</p><p><strong>What actually changed.</strong></p><p>Two things happened closely enough together that most takes collapse them into one.</p><p>The first is unglamorous. Companies overhired through the pandemic, then stopped, and a large pool of experienced engineers came loose at the same moment. <a href="https://www.signalfire.com/blog/signalfire-state-of-talent-report-2026">SignalFire&#8217;s 2026 talent report</a> puts new-graduate hiring down 65 percent at the largest tech companies and 76 percent at early-stage startups against a 2019 baseline, and reads it as a structural reset rather than a dip. Selectivity by itself raises a bar. No technology story is required for that part.</p><p>The second is the interesting half. Agents started producing &#8220;it works&#8221; for free.</p><p>The signal did not get easier to fake. It stopped being a signal. If an agent can produce a functioning CRUD feature in an afternoon, a functioning CRUD feature says nothing about the person who submitted it. The proxy the entire entry-level pipeline rested on evaporated, and what is left underneath is the thing the tutorial path never charged anyone for: knowing why it works, and being able to tell when it does not.</p><p>That cost shows up in aggregate now. <a href="https://stackoverflow.blog/2025/12/29/developers-remain-willing-but-reluctant-to-use-ai-the-2025-developer-survey-results-are-here/">Stack Overflow&#8217;s 2025 survey</a> of more than 49,000 developers has adoption at 80 percent while trust in accuracy fell from 40 to 29 percent, with 45 percent naming &#8220;almost right, but not quite&#8221; as their leading frustration. Generation got cheap. Verification did not, and verification is fundamentals wearing a different hat.</p><p>I am not claiming AI caused this. It landed on a market that was already correcting, and its contribution was narrower: it made the missing understanding impossible to hide. <a href="https://addyosmani.com/blog/next-two-years/">Addy Osmani</a> describes entry-level engineers &#8220;skipping the hard way,&#8221; never building the thing from scratch, never debugging the memory leak alone. And a <a href="https://www.globenewswire.com/news-release/2026/06/11/3310571/0/en/only-16-of-senior-developers-say-junior-engineers-fully-understand-ai-generated-code-bairesdev-survey-finds.html">June survey from BairesDev</a>, which comes from a staffing company with an interest in the answer and should be read that way, asked 1,569 developers across 77 countries and found only 16 percent of senior engineers believe juniors fully understand the AI-generated code they submit.</p><p>I saw it in about fifteen people. That one found it in fifteen hundred.</p><h2>Where the pitch is right</h2><p>Three things, and they get real weight.</p><p><strong>It genuinely worked, and calling it a scam in hindsight is dishonest.</strong> A window was open and people climbed through it, and the ones who did owe nobody an explanation for having noticed. Then it closed. That is a different thing from a lie being found out.</p><p><strong>The anti-credential half held.</strong> Nobody responded to this correction by replacing the bootcamp graduate with a computer science graduate. The CS graduates turned up with the same gaps, which is exactly what my own wrong assumption was about. The door still does not require a degree, and given how much of the professional world runs on credentials, that is not a small thing to still be true.</p><p><strong>It is still the least gated door available.</strong> Entering software on demonstrated skill alone remains unusually possible next to law, medicine, or structural engineering, where the gate is statutory and no amount of talent walks around it. What closed was the shortcut. The door is where it always was.</p><h2>What I&#8217;d actually do today</h2><p><strong>Use the agent to learn, not only to build.</strong> After the thing works, stay in the conversation. Ask why it chose that approach, what it rejected, what breaks if you do it the other way. Ask it to explain the SQL it generated, the auth flow it assumed, the header it set. You have access to the thing that used to require a senior engineer sitting beside you with the patience to be interrogated, and it is now free and endlessly patient, and almost nobody uses it that way. <em>Cost:</em> slower than accepting the diff, and nobody will ever check that you did it. Which is exactly why it is worth something.</p><p><strong>For anything you ship, be able to describe the layer underneath it.</strong> Shipped a query through an ORM? Read the SQL it emitted, then read the plan. Shipped an endpoint? Know who can call it and how someone would try. You do not have to go all the way down. One layer, every time. <em>Cost:</em> you will regularly discover you were wrong about something you were sure of, which is unpleasant and is also the entire mechanism by which this works.</p><p><strong>When something tells you to turn a thing off, find out what the thing does first.</strong> Every disabled setting in a tutorial is a decision somebody made for you, in a context that is not yours, to keep their example short. <em>Cost:</em> an afternoon on the same-origin policy instead of a finished feature. Take the afternoon. That afternoon is the difference between the two candidates I interview.</p><p>And keep building. Building was never the bad advice. It just stopped being the whole of it.</p><blockquote><p>For a decade the bar was &#8220;it works.&#8221; That was never a bar. It was a receipt.</p></blockquote><div><hr></div><p><em>Reverse Pitch is one post a week on software engineering and the career around it, written from inside the work. Opinions, with receipts.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Reverse Pitch on "AI Writes the Code for You"]]></title><description><![CDATA[The demo is real. So is the bill it doesn't show you.]]></description><link>https://www.reversepitch.io/p/the-reverse-pitch-on-ai-writes-the</link><guid isPermaLink="false">https://www.reversepitch.io/p/the-reverse-pitch-on-ai-writes-the</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Wed, 16 Sep 2026 12:19:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ti8p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ti8p!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ti8p!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 424w, https://substackcdn.com/image/fetch/$s_!ti8p!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 848w, https://substackcdn.com/image/fetch/$s_!ti8p!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 1272w, https://substackcdn.com/image/fetch/$s_!ti8p!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ti8p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png" width="1200" height="680" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:680,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66791,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.reversepitch.io/i/215978904?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ti8p!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 424w, https://substackcdn.com/image/fetch/$s_!ti8p!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 848w, https://substackcdn.com/image/fetch/$s_!ti8p!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 1272w, https://substackcdn.com/image/fetch/$s_!ti8p!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a1e2d0-085a-4889-bb1a-132197ac90f0_1200x680.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Every technology shows up with a pitch attached. Someone stands on a stage, describes a world where the hard part is gone, and for a while the room believes it. Reverse Pitch is about what that same technology looks like once it&#8217;s in production, under real traffic, on a real bill.</p><p>We start with the biggest pitch on the table.</p><h2>The pitch</h2><p>The claim is not that language models are useful. That one is settled. The claim is stronger than that: coding agents write the code now. You describe the feature, the agent plans it, edits across the repo, runs the tests, fixes what it broke, and opens the pull request. The engineer moves up a level, from writing software to specifying it.</p><p>And the demo works. That&#8217;s the uncomfortable part. Hand an agent a well-scoped CRUD endpoint in a codebase with clear conventions and it will produce something close to what you&#8217;d have written, in a fraction of the time, with tests. I&#8217;ve watched it happen. Anyone telling you the demos are fake hasn&#8217;t run one.</p><p>So the pitch isn&#8217;t a lie. It&#8217;s a measurement taken under conditions that don&#8217;t survive contact with a real codebase.</p><h2>The reality</h2><p>I&#8217;ve spent the last eight months using coding agents on production work: established systems, greenfield projects that made it to production, and personal ones. Here&#8217;s what the ledger actually looks like.</p><p><strong>The speedup is real, but not where the pitch says it is.</strong></p><p>What got dramatically faster was the work I already knew how to do and didn&#8217;t want to do. The DRF serializer for a model I&#8217;d already designed, a backfill script, the scaffolding for a new project. On that class of task, an afternoon of work now takes less than an hour.</p><p>What got slower was the work I hadn&#8217;t finished thinking about. When I handed an agent a problem I didn&#8217;t fully understand, I got a confident, plausible, well-formatted implementation of the wrong thing. Then I spent the afternoon I&#8217;d just saved reading it closely enough to realize it was wrong. Reviewing code you didn&#8217;t write is slower than writing it. That cost never shows up in the demo, because in the demo the specification was already correct.</p><p><strong>The unmaintainable-project failure mode is structural, not a skill issue.</strong></p><p>Ask for a feature without architectural constraints and you get code that works and doesn&#8217;t belong. On larger codebases I hit this constantly: an N+1 query introduced because the agent couldn&#8217;t see the access pattern behind an imported dependency, a duplicate helper written because it didn&#8217;t know the utility already existed. Each instance is small. The problem is that each one is individually reasonable, so nothing trips your review instinct, and sixty of them arrive in a week.</p><p>The fix is organizational rather than personal, which is what makes it hard. Keeping a codebase legible to an agent is a convention every engineer follows, not a document one engineer writes. At enterprise scale that&#8217;s a company-wide change, and company-wide changes take quarters. The models ship faster than that. By the time the rules are actually enforced, they were written for a model two generations back.</p><p><strong>Context is the bill.</strong></p><p>The most expensive thing about agentic coding is not the subscription. It&#8217;s that useful output requires the model to hold your architecture in its head, and holding your architecture in its head costs tokens on every single turn. A single deep session on a mature repo burns 40 to 50% of my usage window of a Max subscription. Multiply that across a team and the &#8220;just use AI&#8221; line item stops being a rounding error.</p><p>The counterintuitive part: the fix for bad output is usually <em>more</em> context, which is also the thing that costs money. The cheap prompt gives you the result you have to throw away.</p><p><strong>What I got wrong.</strong></p><p>I assumed supervision was enough on its own: that I could skip the design thinking as long as I read every diff. It isn&#8217;t. Letting the agent choose the abstraction and reviewing only the result meant closing tasks faster while understanding the system less, and after a few weeks of it I found reviewing code I hadn&#8217;t written more draining than writing it myself, even when writing it myself took longer.</p><h2>Where the pitch is right</h2><p>Three conditions, and when all three hold I&#8217;ll take the agent every time.</p><p><strong>The problem is already solved in your head.</strong> If you can describe the implementation in a single paragraph, the agent is faster than you and the review is cheap. Not the feature. The implementation.</p><p><strong>The codebase has enforced conventions.</strong> Not documented ones. Enforced ones: linters, type checks, a test suite that fails loudly, a directory structure that makes the wrong thing awkward. Agents follow the constraints that exist in the repo, not the ones in the README. Every hour spent making a convention mechanical pays back on every future generation.</p><p><strong>The blast radius is small and the feedback is fast.</strong> Scripts, migrations you can review in one screen, test coverage, one-off data work, the tedious middle of a refactor you&#8217;ve already planned. Low stakes and immediate signal is exactly where the technology is strongest.</p><p>That&#8217;s a genuinely large fraction of the job. The pitch oversells it by suggesting it&#8217;s <em>all</em> of the job.</p><h2>What I&#8217;d actually do today</h2><p>Four rules. Each one costs something, and the cost is the point.</p><p><strong>Argue before you delegate.</strong> Think the problem through and reach your own solution first. Then don&#8217;t hand it over. Open a planning session, give the agent the constraints without your answer, and let it propose one. Now you have two solutions to compare, and a real technical discussion of the kind you&#8217;d have with a coworker at a whiteboard. Put a clock on it. Ten minutes is usually enough to land on something neither of you would have reached alone: better than mine because of what the model was trained on, better than its because of what I know about the project. <em>Cost:</em> you give up the fantasy of describing a feature in one sentence and getting it back. That fantasy was never real.</p><p><strong>Make one thing mechanical every week.</strong> A lint rule, a test, a project convention that fails CI. <em>Cost:</em> an hour that produces no visible feature. It&#8217;s the highest-leverage hour in the week, because it constrains every generation after it.</p><p><strong>Read the diff as if you&#8217;re reviewing a contractor&#8217;s first PR.</strong> Not &#8220;does this work&#8221; but &#8220;does this belong in the system I&#8217;m responsible for.&#8221; Reject on architecture, not just correctness. <em>Cost:</em> you will reject working code, and it will feel wasteful. Reject it anyway.</p><p><strong>Keep one thing a week that you build entirely yourself.</strong> The data layer of a new feature, the base implementation of a pattern everything else will extend. The parts where the design decision <em>is</em> the work. <em>Cost:</em> it&#8217;s slower. That&#8217;s what you&#8217;re paying for. The judgment that makes you worth asking is built by doing the hard part, and it&#8217;s the only asset here that doesn&#8217;t depreciate when the next model ships.</p><blockquote><p>The agent isn&#8217;t the junior engineer in this story. You are the senior one, and the whole value of that role is knowing what should exist before anything gets written. That part hasn&#8217;t been automated. It&#8217;s just been made much easier to skip.</p></blockquote><div><hr></div><p><em>Reverse Pitch is one post a week on software engineering and the career around it, written from inside the work. Opinions, with receipts.</em></p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Clean Code: One Size Doesn’t Fit All]]></title><description><![CDATA[The real essence of clean code lies in the ability to communicate the intent of the program clearly to other engineers.]]></description><link>https://www.reversepitch.io/p/clean-code-one-size-doesnt-fit-all</link><guid isPermaLink="false">https://www.reversepitch.io/p/clean-code-one-size-doesnt-fit-all</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Fri, 26 Jul 2024 13:31:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Hnaj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Clean code isn&#8217;t just a buzzword or some hot topic that arise now and then&#8202;&#8212;&#8202;it&#8217;s a critical element in building maintainable and scalable systems. Pairing it with thorough code reviews, it becomes an incredible asset for any development team, enhancing both the quality of the software and the efficiency of the team.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Hnaj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Hnaj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!Hnaj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!Hnaj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!Hnaj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Hnaj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png" width="800" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;To make a pile of code blocks represent a tower, you have to adapt some pieces. Generated by AI&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="To make a pile of code blocks represent a tower, you have to adapt some pieces. Generated by AI" title="To make a pile of code blocks represent a tower, you have to adapt some pieces. Generated by AI" srcset="https://substackcdn.com/image/fetch/$s_!Hnaj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 424w, https://substackcdn.com/image/fetch/$s_!Hnaj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 848w, https://substackcdn.com/image/fetch/$s_!Hnaj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 1272w, https://substackcdn.com/image/fetch/$s_!Hnaj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2585d38d-abe2-4445-8a23-b5ba65c69447_800x800.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">To make a pile of blocks represent a tower, you may have to adapt some pieces. Generated by&nbsp;AI</figcaption></figure></div><h3>What is Clean&nbsp;Code?</h3><p>Clean code is not following a style guide or some naming convention, although these are very important aspects. At its core, clean code is about writing code that is easy to understand, maintain and extend. It emphasizes clarity, simplicity, and consistency, making it easier for developers to understand and work with.</p><p>Books like Robert C. Martin&#8217;s &#8220;Clean Code&#8221; and Steve McConnell&#8217;s &#8220;Code Complete&#8221; provide extensive guidelines on writing clean code. Both of these books offer valuable insights, but it&#8217;s essential to remember that they are guidelines, not commandments.</p><p>The real essence of clean code lies in the ability to communicate the intent of the program clearly to other engineers (yes, including your future self). However, the interpretation for it can vary depending on the project context.</p><h3>The Importance of&nbsp;Context</h3><p>To understand the importance of context, let&#8217;s consider Google, one of the world&#8217;s leading tech companies. Their approach to clean code demonstrates the importance of context when writing code.</p><p>At Google, developers often need to sacrifice certain aspects of readability for the sake of performance. Why? Because they are building tools and services that are used by millions of users concurrently, requiring every bit of performance they can squeeze.</p><p>Within this context, writing &#8220;clean code&#8221; requires you to take a different road (but you should reach the same goal). This might involve:</p><ul><li><p>Using less intuitive but more performant data structures.</p></li><li><p>Implementing complex optimizations that may reduce readability.</p></li><li><p>Favoring efficiency over conventional coding patterns.</p></li></ul><p>This doesn&#8217;t mean the code is &#8220;unclean&#8221;. Rather, it&#8217;s clean within its specific context, optimized for the constraints and requirements of large-scale, high-performance systems.</p><p>Following every fancy article or book from renown engineers may be tempting but remember that your role is not to blindly apply these suggestions (which by no means are bad), but to:</p><ol><li><p>Understand the implementation context of each project.</p></li><li><p>Identify the most critical requirements (e.g., readability, performance, security)</p></li><li><p>Apply appropriate coding guidelines and patterns that align with these requirements.</p></li><li><p>Balance different aspect of code quality to achieve the best overall result.</p></li></ol><p>This approach requires critical thinking and often involves making trade-offs. Sometimes, you might prioritize readability and simplicity. Other times, like in Google&#8217;s case, you might lean towards performance optimizations.</p><h3>The Value of Code&nbsp;Reviews</h3><p>Code reviews play a crucial role in maintaining code quality within a specific context. It serves multiple purposes:</p><ol><li><p>Ensuring that every piece of code introduced adheres to the specific coding standards (some of these can certainly be automated through linters and formatters).</p></li><li><p>Catching bugs and potential issues early.</p></li><li><p>Sharing knowledge among team members.</p></li></ol><p>Let&#8217;s include a fourth purpose, which is confirming whether or not you reached the goal of writing understandable, maintainable and extendable code.</p><p>While code reviews focus on specific requirements and constraints of the project, isn&#8217;t it the best place to consider if my fellow team members are able to work with this piece of code introduced?</p><p>Reviewers should understand the context in which the code operates and evaluate it accordingly. Only then, code reviews evolve into a crucial piece for building software.</p><h3>Conclusion</h3><p>Building great software is inherently a collaborative effort, but aligning multiple minds towards the same goal is often more challenging than it appears. Writing &#8220;clean code&#8221; is, in essence, a team endeavor. It begins with one engineer crafting code that they believe aligns with the project&#8217;s constraints and coding best practices. The process continues as another team member reviews this code, offering valuable feedback and insights.</p><p>By understanding the unique needs of each project and applying clean code principles judiciously, we can create codebases that are truly &#8220;clean&#8221; in the ways that matter most for their specific contexts. This nuanced approach to clean code and code reviews leads to more effective, efficient, and maintainable software systems.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Comparing Programming Languages]]></title><description><![CDATA[Get to know the tools in your belt to build efficient, scalable and maintainable software.]]></description><link>https://www.reversepitch.io/p/comparing-programming-languages</link><guid isPermaLink="false">https://www.reversepitch.io/p/comparing-programming-languages</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Thu, 18 Jul 2024 18:08:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hMsm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As software engineers, choosing the right programming language, to learn or for a specific project, is critical for efficient, scalable and maintainable software. Different programming languages excel in different areas, and understanding their strengths and weaknesses can significantly impact the success of your projects. Today, we will be covering some of the most popular programming languages and highlight their ideal use cases.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hMsm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hMsm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hMsm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hMsm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hMsm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hMsm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg" width="800" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hMsm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hMsm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hMsm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hMsm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1983e685-5641-4a0d-9708-f74f5c32699c_800x800.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Get to know the tools in your belt. Generate by&nbsp;AI</figcaption></figure></div><h3>Python: The Versatile Workhorse</h3><p>It is very good in Data Science, Machine Learning, Automation, Scripting and Web Development.</p><h4>Why It&#8217;s&nbsp;Good?</h4><ul><li><p><strong>Ease of use: </strong>Python&#8217;s syntax is simple and readable, making it an excellent choice for new engineers and for rapid development.</p></li><li><p><strong>Libraries and frameworks.</strong> A vast ecosystem of libraries and frameworks, such as Django and Flask for web development; NumPy, pandas and TensorFlow for data science and machine learning.</p></li><li><p><strong>Community support: </strong>A large and active community means a lot of resources and tutorials. Based on Stack Overflow statistics, the top tag from questions in the past 3 years is Python.</p></li></ul><h4>What It&nbsp;Lacks?</h4><ul><li><p><strong>Performance</strong>: Python is generally slower than compiled languages like C++ or Java due to its interpreted nature.</p></li><li><p><strong>Mobile Development</strong>: While possible, mobile app development in Python is not robust at all and choosing other languages like Swift or Kotlin are way better choices.</p></li></ul><p><em>Ranked 1 in popularity as programming language (PYPL).</em></p><h3>Java: Enterprise Staple</h3><p>Use very frequently on enterprise applications, android development and large-scale systems.</p><h4>Why It&#8217;s&nbsp;Good?</h4><ul><li><p><strong>Platform Independence: </strong>Java&#8217;s motto is &#8220;write once, run anywhere&#8221;. This is thanks to the JVM which is a major advantage for cross-platform development.</p></li><li><p><strong>Robustness and Scalability: </strong>Java&#8217;s strong memory management and scalability make it ideal for large and complex enterprise systems.</p></li><li><p><strong>Mature Ecosystem: </strong>A mature ecosystem with battle-tested frameworks like Sprint and Hibernate enable rapid development, integration and support.</p></li></ul><h4>What It&nbsp;Lacks?</h4><ul><li><p><strong>Conciseness: </strong>Java is often criticized for its verbosity, which can lead to more boilerplate code compared to languages like Python or Kotlin.</p></li><li><p><strong>Performance: </strong>Although better than interpreted languages, Java&#8217;s performance if often behind that of C++ or Go for low-level tasks.</p></li></ul><p><em>Ranked 2 in popularity as programming language (PYPL).</em></p><h3><strong>JavaScript: The King of the&nbsp;Web</strong></h3><p>Best use cases are front-end web development, back-end development (with Node.js) and mobile development (with React Native).</p><h4>Why It&#8217;s&nbsp;Good?</h4><ul><li><p><strong>Versatility: </strong>With the advent of Node.js, JavaScript can now be used for server-side development, unifying both stacks.</p></li><li><p><strong>Rich Ecosystem: </strong>Frameworks like React, Angular and Vue.js revolutionize front-end development, while Express.js, NestJS and Fastify powers back-end services.</p></li><li><p><strong>Speed:</strong> Node.js, with its event-driven, non-blocking I/O model and single-threaded event loop, can handle multiple concurrent requests efficiently, making it fast and lightweight for I/O-bound tasks.</p></li></ul><h4>What It&nbsp;Lacks?</h4><ul><li><p><strong>CPU Performance</strong>: For computation-heavy applications, JavaScript may not be as performant as languages designed for such tasks, like C++.</p></li><li><p><strong>Language Stability: </strong>JavaScript has evolved to cover all bases, and even though that provides a great benefit, it also comes with drawbacks when moving to use-cases that were not part of JavaScript initial conception. Inheritance, incompatible API updates and nested callbacks are some of the common issues that arise when moving JavaScript to the servers (through Node.js).</p></li></ul><p><em>Ranked 3 in popularity as programming language (PYPL).</em></p><h3>C++: Performance Powerhouse</h3><p>One of the best programming languages for CPU-bound tasks, game development and real-time systems.</p><h4>Why It&#8217;s&nbsp;Good?</h4><ul><li><p><strong>Performance: </strong>As a compiled language, it offers excellent performance and fine-grained control over system resources.</p></li><li><p><strong>Memory Management: </strong>Direct memory manipulation using pointers allow for system-level programming and optimizations.</p></li><li><p><strong>Game Development:</strong> Unreal Engine, a leading game development engine is built using C++ due to its high performance and control.</p></li></ul><h4>What It&nbsp;Lacks?</h4><ul><li><p><strong>Simplicity: </strong>C++ is by no means a simple language, especially when delving into more complex concepts like pointers, manual memory management and multiple inheritances.</p></li><li><p><strong>Development Speed: </strong>Writing, debugging and maintaining C++ code can be more time-consuming than higher-level languages.</p></li></ul><p><em>Ranked 5 in popularity as programming language (PYPL).</em></p><h3>PHP: Backbone of the&nbsp;Web</h3><p>It is used for server-side web development, CMS and e-commerce platforms.</p><h4>Why It&#8217;s&nbsp;Good?</h4><ul><li><p><strong>Web Focus</strong>: PHP is specifically designed for server-side web development and excels in this domain. It has been laser-focus on the same niche therefore creating a strong backbone.</p></li><li><p><strong>CMS:</strong> Many popular content management systems, such as WordPress and Joomla are built on PHP, providing a vast ecosystem of plugin and themes.</p></li></ul><h4>What It&nbsp;Lacks?</h4><ul><li><p><strong>Modern Features: </strong>It has been criticized for lacking some modern features, although recent versions may have addressed some of these.</p></li><li><p><strong>Concurrency: </strong>PHP execution model is not well-suited for handling large number of concurrent connections like Node.js.</p></li></ul><p><em>Ranked 7 in popularity as programming language (PYPL).</em></p><h3>Go: Concurrency King</h3><p>It is very good for cloud services, DevOps tools and system tools.</p><h4>Why It&#8217;s&nbsp;Good?</h4><ul><li><p><strong>Concurrency: </strong>It&#8217;s built to support concurrent programming making it ideal for network servers and other concurrent tasks.</p></li><li><p><strong>Simplicity and Efficiency: </strong>Go is designed for simplicity and efficiency, with a clean syntax and fast complication times.</p></li><li><p><strong>Scalability: </strong>Go&#8217;s performance and efficient memory management make it suitable for large-scale systems.</p></li></ul><h4>What It&nbsp;Lacks?</h4><ul><li><p><strong>Standard Library: </strong>Go&#8217;s standard library is limited and often requires manual implementations for tasks that are usually available out-of-the-box in Python or Java.</p></li><li><p><strong>Learning Curve: </strong>Go introduce some unique concepts that may take time for developers to wrap in their heads. It may take more time to adopt Go if you come from other language.</p></li></ul><p><em>Ranked 12 in popularity as programming language (PYPL).</em></p><h3>Conclusion</h3><p>Choosing the right programming language hinges on the specific requirements and constraints of your project. While Python shines in data science and machine learning, JavaScript dominates web development. Java remains a strong choice for enterprise applications, and C++ is unparalleled for performance-critical tasks.</p><p>Understanding the strengths and limitations of each language empowers software engineers to make informed decisions, leading to more effective and efficient software development.</p><h3>References</h3><ul><li><p><a href="https://stackoverflow.blog/2023/01/26/comparing-tag-trends-with-our-most-loved-programming-languages/">Comparing tag trends with our Most Loved programming languages&#8202;&#8212;&#8202;Stack Overflow</a></p></li><li><p><a href="https://pypl.github.io/PYPL.html">PYPL PopularitY of Programming Language index</a></p></li></ul><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/p/comparing-programming-languages?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.reversepitch.io/p/comparing-programming-languages?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Getting Started with Celery: A Comprehensive Guide]]></title><description><![CDATA[Celery is a powerful, open-source, asynchronous task queue based on distributed messaging.]]></description><link>https://www.reversepitch.io/p/getting-started-with-celery-a-comprehensive</link><guid isPermaLink="false">https://www.reversepitch.io/p/getting-started-with-celery-a-comprehensive</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Wed, 10 Jul 2024 18:47:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!0Dff!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0Dff!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0Dff!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0Dff!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0Dff!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0Dff!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0Dff!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg" width="800" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0Dff!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!0Dff!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!0Dff!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!0Dff!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb9576ad-f3de-4859-8435-75f824aaf50f_800x800.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Representation of Python Celery generated by&nbsp;AI</figcaption></figure></div><p>Celery is a powerful, open-source, asynchronous task queue based on distributed messaging. It focuses on real-time operation but supports scheduling as well. It is normally paired with web frameworks like Django or Flask to handle time consuming tasks outside of the web request/response cycle.</p><p>At its core, Celery is designed to handle tasks in the background, making it ideal for uses-cases in which you need to offload tasks to run them efficiently. Celery is highly flexible and can be integrated with a couple of messaging brokers like RabbitMQ and Redis.</p><h3>Common Use&nbsp;Cases</h3><p>Let&#8217;s go over some common use cases for Celery:</p><h4>1. Sending&nbsp;Emails</h4><p>Sending emails is a time-consuming task that can slow down your server&#8217;s response time if processed synchronously (waiting for the email to be sent to return a response). Celery allows you to send emails in the background, improving the user experience by making your application more responsive.</p><h4>2. Generating Reports</h4><p>Generating large reports can take significant amount of time, from fetching all the required data to transforming it into a visually effective report. Using Celery, you can delegate the report generation process in the background and notify the users once the report is ready to download (or send it via email).</p><h3>Code Examples</h3><p>Let&#8217;s dive into some code and see how Celery works. We will implement a simple Flask application for this example.</p><h4>1. Install Celery and&nbsp;Redis</h4><p>First, you need to install Celery and your message broker (for this example we will be using Redis)</p><pre><code>pip install celery redis Flask</code></pre><h4>(Optional) Run Redis using&nbsp;Docker</h4><p>Since you will need a Redis instance to start hacking with Celery, a good option is to spin it up using Docker. If you already have Docker installed, simply run the following command:</p><pre><code>docker run -d --name redis -p 6379:6379 redis</code></pre><p>This command will:</p><ul><li><p>Download the Redis image if it&#8217;s not already present on your system.</p></li><li><p>Run the Redis server in detached mode (<code>d</code>), mapping the default Redis port 6379 from the container to your host machine.</p></li></ul><h4>2. Create Flask Application</h4><p>Let&#8217;s create a simple Flask application in <code>app.py</code>:</p><pre><code>from flask import Flask, request, jsonify
from celery import Celery

app = Flask(__name__)

# Configure Celery
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'

celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)

@celery.task
def send_email(recipient):
    # Simulate email sending
    import time
    time.sleep(5)
    return f'Email sent to {recipient}'

@app.route('/send-email', methods=['POST'])
def send_email_route():
    data = request.get_json()
    recipient = data['recipient']
    task = send_email.delay(recipient)
    return jsonify({ 'task_id': task.id }), 202

@app.route('/status/&lt;task_id&gt;')
def task_status(task_id):
    task = send_email.AsyncResult(task_id)
    if task.state == 'PENDING':
        response = {'state': task.state, 'status': 'Pending...'}
    elif task.state != 'FAILURE':
        response = {'state': task.state, 'result': task.result}
    else:
        response = {'state': task.state, 'status': str(task.info)}
    return jsonify(response)

if __name__ == '__main__':
    app.run(debug=True)</code></pre><h4>3. Run Flask and Celery&nbsp;Worker</h4><p>Run your Flask application:</p><pre><code>python app.py</code></pre><p>In a new terminal, start the Celery worker:</p><pre><code>celery -A app.celery worker --loglevel=info</code></pre><p>Let&#8217;s describe the whole flow:</p><ol><li><p>A client makes a POST request to <code>/send_email </code>with a JSON body containing the recipient&#8217;s email.</p></li><li><p>The Flask application will process the request and trigger a Celery task.</p></li><li><p>The Celery worker will receive the task and start the &#8220;processing&#8221; of sending an email.</p></li><li><p>There is an extra endpoint <code>/status/&lt;task_id&gt;</code> which allows the client to check the status of the task.</p></li></ol><h3>Benefits of Using&nbsp;Celery</h3><p>The above example is an oversimplification of what you can do with Celery, but even so, we can mention a whole list of benefits from it:</p><h4>Asynchronous Processing</h4><p>Celery allows task to be executed asynchronously, which can greatly enhance the performance of your server application. In a real-world scenario, in which you have a lot of customers executing actions that requires time-consuming operations, moving those operations to the background can avoid your app to get bloated of requests, impacting the experience of your customers.</p><h4>Scalability</h4><p>Celery is designed to be highly scalable, allowing you to distribute tasks across multiple workers (even on different machines). This allows you to horizontally scale your worker pool for tasks that are more demanding without increasing your application server as a whole.</p><h4>Scheduling</h4><p>In addition to these real-time tasks, Celery supports scheduling, making it easy to run periodic tasks.</p><h3>Challenges of Using&nbsp;Celery</h3><p>There is no silver bullet in technology, therefore we can&#8217;t ignore the intrinsic challenges from adding a new tool to your stack.</p><h4>Complexity</h4><p>Setting up and managing a distributed task queue can add complexity to your application.</p><h4>Error Handling</h4><p>Proper error handling and monitoring are essential to ensure that tasks are not failing silently. Celery supports retry logic and a couple of error handling mechanism, but it&#8217;s up to you to use them correctly.</p><h4>Dependency</h4><p>Celery relies on external message broker (Redis, RabbitMQ, etc.), therefore it may include a dependency to your project.</p><h3>Conclusion</h3><p>Celery is an invaluable tool for any Python developer looking to handle asynchronous tasks and improve the performance of their applications. While it does introduce some complexity, the benefits of using Celery often outweigh the challenges, especially for applications that require efficient task management.</p><p>By following this guide, you should now have a basic understanding of how to set up and use Celery in your Python projects. Whether you&#8217;re sending emails, generating reports, or handling any other background tasks, Celery can help you manage these tasks efficiently and effectively.</p>]]></content:encoded></item><item><title><![CDATA[The role of AI in software development]]></title><description><![CDATA[Coding in the Age of AI: Opportunities and Challenges]]></description><link>https://www.reversepitch.io/p/the-role-of-ai-in-software-development</link><guid isPermaLink="false">https://www.reversepitch.io/p/the-role-of-ai-in-software-development</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Wed, 26 Jun 2024 11:01:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!mrz9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mrz9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mrz9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!mrz9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!mrz9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!mrz9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mrz9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg" width="800" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mrz9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 424w, https://substackcdn.com/image/fetch/$s_!mrz9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 848w, https://substackcdn.com/image/fetch/$s_!mrz9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!mrz9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd74a6c16-307e-481c-9244-fee3d3ffe8b1_800x800.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Generated using AI, because why not?</figcaption></figure></div><p>Artificial Intelligence (AI) is becoming an increasingly integral part of the software development process, bringing both exciting opportunities and significant challenges. In this evolving landscape, understanding how AI can elevate your work&#8202;&#8212;&#8202;from automating boring tasks to supercharging software development&#8202;&#8212;&#8202;is essential. However, it is equally important to remain aware of the potential pitfalls, such as the risk of reducing engineers to mere operators of AI-driven tools.</p><p>This article delves into the transformative role of AI in software development. We&#8217;ll explore how this technology is reshaping the developer&#8217;s toolkit and landscape, examine its current capabilities and limitations, and consider its implications for the future of the industry.</p><h3>AI in Development Tools</h3><p>AI tools are revolutionizing the software development process by automating repetitive tasks such as code generation, bug detection, and testing. While these tools are becoming increasingly popular, their effectiveness depends heavily on the hands that wield them. As an engineer, you need to thoroughly understand and analyze the requirements and constraints of your software project. Using AI tools can assist you with repetitive tasks and provide missing pieces of knowledge, creating a powerful synergy between human intuition and AI assistance.</p><p>However, the relationship between developers and AI tools can become toxic when engineers start relying too heavily on these digital assistants, <strong>sacrificing their critical thinking </strong>in the process. It&#8217;s important to remember that these are tools meant to aid, not replace, human creativity. In the current state of AI, and for the foreseeable future, engineers remain the essential minds behind software development, harnessing these tools to enhance their work effectively.</p><p>Think of it this way: you shouldn&#8217;t ask AI to construct an entire house; instead, you might task it with designing a door. It&#8217;s your responsibility as an engineer to ensure that the door is placed correctly and meets all necessary specifications.</p><p>To use AI tools efficiently and avoid the trap of overreliance, consider asking yourself these critical questions before accepting generated code or ideas:</p><ul><li><p><strong>Do I fully understand the requirements of what I need to create or write?</strong></p></li><li><p><strong>Can I break down this task into more specific, manageable components?</strong></p></li><li><p><strong>Am I capable of critically evaluating the AI-generated code?</strong></p></li><li><p><strong>Will this AI-generated code integrate seamlessly with our existing codebase and architecture?</strong></p></li></ul><p>By consistently reflecting on these questions, you maintain your role as the architect of your code, using AI as a powerful assistant rather than an autopilot. This approach ensures that you harness the benefits of AI while retaining control and oversight over your projects, leading to more robust and innovative software development.</p><div class="pullquote"><p>GitHub Copilot is a brilliant name. You are still the one driving the plane while being assisted by your&nbsp;copilot.</p></div><h3>AI in Talent&nbsp;Search</h3><p>AI has significantly impacted the talent search for software engineers, reshaping both sides of the coin with positive and negative implications.</p><p>On the recruitment side, AI-powered tools for candidate screening and skill assessment are becoming more prevalent. These tools can speed up the selection process, allowing recruiters to focus on candidates who match the job requirements. However, they can also exclude qualified candidates and may show biases based on the data they were trained on. Therefore, a balanced approach that combines AI with human intuition is essential.</p><p>For candidates, the environment has become more controversial due to what is called <strong>skill inflation</strong>. AI tools can help engineers produce complex code or sophisticated answers to technical questions, potentially masking their true skill levels and making them appear more proficient than they actually are. This makes the recruiter&#8217;s job more challenging, leading to a shift in the recruiting process. Recruiters are adding multiple layers of screening and interviews to delve deeper into a candidate&#8217;s thought process and problem-solving abilities.</p><p>This shift has made both job searching and talent acquisition more complex, sparking debate on whether AI benefits or detriments the recruitment process overall.</p><p>I believe that in this area, it is crucial for both parties to maintain high levels of integrity and honesty to navigate the increasing complexity in acquiring good talent or finding a suitable job.</p><h3>Conclusion</h3><p>Ultimately, the role of AI in software development is a powerful tool that, when used correctly, can greatly enhance the capabilities of engineers and the efficiency of development processes. However, it&#8217;s crucial to approach AI with a balanced perspective, leveraging its strengths while remaining vigilant about its limitations. By doing so, engineers can navigate the evolving landscape of AI in software development with integrity and innovation, ensuring a bright future for the industry.</p>]]></content:encoded></item><item><title><![CDATA[Memory Profiling and Load Testing a Python Application]]></title><description><![CDATA[Optimizing Python Applications: A Guide to Memory Profiling and Load Testing]]></description><link>https://www.reversepitch.io/p/memory-profiling-and-load-testing</link><guid isPermaLink="false">https://www.reversepitch.io/p/memory-profiling-and-load-testing</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Wed, 19 Jun 2024 23:26:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When working on software development, it&#8217;s crucial to ensure your application is both efficient and can handle a large amount of traffic. This is where memory profiling and load testing come into play. They allow us to monitor and optimize the performance of our applications.</p><p>This guide is about profiling and testing using tools that you can run on your computer, which is very useful to detect memory leaks, bugs or under-performing code before pushing to production.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dev Whisper! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><blockquote><p><em>These techniques are not a replacement for cloud monitoring and observability tools, they cover way more ground and provide a lot of insight about your application (but they are also expensive).</em></p></blockquote><h1><strong>Load Testing</strong></h1><p>Load testing is a technique that simulate real-world conditions to understand the behavior of an application under heavy load. It allows engineers to foresee and fix potential performance issues before they affect real users.</p><p>We&#8217;ll be using <code>locust</code> to load test a simple Flask application in order to show how we can simulate real-world scenarios through its powerful, scriptable nature.</p><p>We will need to install some dependencies:</p><pre><code>pip install flask Faker</code></pre><p>Now, let&#8217;s code a simple a Flask application (<code>app.py</code>):</p><pre><code>import random
from faker import Faker
from flask import Flask, jsonify

fake = Faker()
app = Flask(__name__)


def generate_users():
    """
    Generate a list of random users.
    """
    users = []
    for i in range(100):
        users.append(
            {
                "id": i,
                "name": fake.name(),
                "age": random.randint(18, 99),
                "email": fake.email(),
            }
        )

    return users


def generate_user(user_id: int):
    """
    Generate a random user by ID.
    """
    return {
        "id": user_id,
        "name": fake.name(),
        "age": random.randint(18, 99),
        "email": fake.email(),
    }


@app.route("/users", methods=["GET"])
def list_users():
    """
    List users endpoint.
    """
    return jsonify({"status": 200, "users": generate_users()})


@app.route("/users/&lt;int:user_id&gt;", methods=["GET"])
def get_user(user_id: int):
    """
    Get user by ID endpoint.
    """
    return jsonify({"status": 200, "user": generate_user(user_id)})


if __name__ == "__main__":
    app.run(debug=False)</code></pre><p>We can run this application by simply executing: <code>python app.py</code>.</p><p>You can perform a <code>GET /users</code> request to visualize the list of users:</p><pre><code># Using cURL
curl localhost:5000/users

# Or simply visit &lt;http://localhost:5000/users&gt; in your browser</code></pre><p>Now that we have an application to put under load test, let&#8217;s get started with <code>locust</code>. First, let&#8217;s install it:</p><pre><code>pip install locust</code></pre><p>Once installed, we&#8217;ll write a <code>locustfile.py</code> that defines the behavior of our simulated users. In the script, we&#8217;ll specify the endpoints that locust should hit and the wait time before each defined task.</p><pre><code>import random
from locust import HttpUser, task, between


class SimulatedUser(HttpUser):
    wait_time = between(1, 5)

    @task(1)
    def view_users(self):
        self.client.get("/users")

    @task(4)
    def view_user_by_id(self):
        user_id = random.randint(1, 100)
        self.client.get(f"/users/{user_id}")</code></pre><p>The above code presents an example of how to use Locust, a popular load testing tool, with a Flask application. Here is a detailed description of the key concepts involved:</p><ul><li><p><strong>HttpUser</strong>: This is a class represents a simulated user and they should mimic real world users. In the script, we define a class <code>SimulatedUser</code> that inherits from <code>HttpUser</code>.</p></li><li><p><strong>Task</strong>: The <code>task</code> decorator is used to specify methods that the <code>HttpUser</code> should execute when simulating a user.</p></li><li><p><strong>wait_time</strong>: This is a property of the <code>HttpUser</code> class that specifies how long a simulated user should wait between executing tasks.</p></li></ul><p>We can now run our Locust script by simply executing:</p><pre><code>locust -f locustfile.py</code></pre><p>This will spin up a web interface at <a href="http://localhost:8089">http://localhost:8089</a> in which you can specify your testing arguments as follow:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pDaQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pDaQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 424w, https://substackcdn.com/image/fetch/$s_!pDaQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 848w, https://substackcdn.com/image/fetch/$s_!pDaQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 1272w, https://substackcdn.com/image/fetch/$s_!pDaQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pDaQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png" width="700" height="370" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:370,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!pDaQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 424w, https://substackcdn.com/image/fetch/$s_!pDaQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 848w, https://substackcdn.com/image/fetch/$s_!pDaQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 1272w, https://substackcdn.com/image/fetch/$s_!pDaQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d49637d-8636-4893-b6a0-0d2be440e52b_700x370.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Locust web interface</figcaption></figure></div><p>In this interface, we define three main arguments:</p><ul><li><p><strong>Number of users</strong>: Total number of users you want to simulate at peak concurrency.</p></li><li><p><strong>Ramp up:</strong> The number of users that will be simulated per seconds (in our example it means that 10 new users will be added to the load each second until they reach the peak which is 1000).</p></li><li><p><strong>Host:</strong> This is the host of your server application that each user will target while executing their tasks. Since our Flask application is running locally on port 5000, the value here is <a href="http://localhost:5000">http://localhost:5000</a></p></li></ul><p>Click the <code>Start</code> button, you Locust will start the load test. The first tab that you will notice is the <code>Statistics</code> one, in which you can view a table with all the requests executed and their response time and some other stats.</p><p>Let&#8217;s move to the <code>Charts</code> tab to get a more friendly representation of your application performance. Here you will get three charts:</p><ul><li><p><strong>Total Requests per Second</strong>: This is basically the number of requests your application is handling per second.</p></li><li><p><strong>Number of Users</strong>: The last chart simply indicates the number of users over time.</p></li><li><p><strong>Response Times (ms):</strong> This is how long your application is taking to response the requests. You will see two lines here:</p><ul><li><p><strong>Average Response Time</strong>: Which as the name states, is the average response time it takes.</p></li><li><p><strong>95th percentile:</strong> Which indicate the response time below which 95% of all recorded response times fall. For example, if the 95th percentile response is 50ms, it means that 95% of the requests were completed in less than 50ms, while the remaining 5% took longer.</p><p><em><br></em>It&#8217;s important that your 95th percentile isn&#8217;t significantly higher than the average response time, since it may indicate performance issues on an important subset of users.</p></li></ul></li></ul><p>There are other tabs in which you can monitor the Failures or Exceptions that may have occur during the tests. This is very important since you can debug possible failures that only happen during heavy-load scenarios.</p><p>Locust also allows you to download the report in a HTML format so you can visualize later and compare it after you have improved your application.</p><h1>Memory profiling</h1><p>Memory profiling consist in analyzing a program&#8217;s memory consumption to identify and solve issues related to unusual memory usage. It helps you understand how you application allocate resources and its very useful when sizing your cloud instances correctly.</p><p>There are multiple tools for memory profiling out there, but for today post, will be using <code>memray</code> because of its ease of use and the various reports it can generate.</p><p>Let&#8217;s install it using <code>pip</code>:</p><pre><code>pip install memray </code></pre><p>Using our Flask application built above, let&#8217;s now perform memory profiling:</p><pre><code>memray run -o result.bin app.py</code></pre><p>Once the application is running, you can perform the load test defined above to simulate a real-world scenario while <code>memray</code> tracks the memory usage.</p><p>After running the load test for a while, simply stop <code>memray</code> (<code>Ctrl + C</code> the process) and it will generate a <code>result.bin</code> file with all the tracked data.</p><p>Now we can generate a report using the following command:</p><pre><code>memray flamegraph result.bin</code></pre><p>This will generate a flame graph in HTML format for you to visualize in your browser. Flame graphs are a visualization of program resource usage that help identify which parts of your code are consuming the most memory during execution.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QMzB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QMzB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 424w, https://substackcdn.com/image/fetch/$s_!QMzB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 848w, https://substackcdn.com/image/fetch/$s_!QMzB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 1272w, https://substackcdn.com/image/fetch/$s_!QMzB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QMzB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png" width="700" height="370" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:370,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!QMzB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 424w, https://substackcdn.com/image/fetch/$s_!QMzB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 848w, https://substackcdn.com/image/fetch/$s_!QMzB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 1272w, https://substackcdn.com/image/fetch/$s_!QMzB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff2a48831-de2d-40d7-a24d-7be4012902b9_700x370.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Flame graph generated by memray</figcaption></figure></div><p>Each block on the x-axis represents a function in the code, with the size of the block representing the amount of memory that function uses. The y-axis represents the stack depth. <code>memray</code> actually defaults to the <code>Icicles</code> view which is basically inverting the y-axis so the root is at the top and the functions at the bottom. You can choose either view based on your preference.</p><p>However, the critical detail to note is the width of the function blocks. The wider a block is, the more memory has been allocated to that function. Therefore, if a block appears unusually wide, it could indicate that a potential memory leak is affecting your application.</p><p>Another very important graph within <code>memray</code> is the memory size over time, which you can see by clicking the header with the orange and blue lines. In this graph you can see the Resident Size and the Heap Size and how much memory is allocated over time.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bffw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bffw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 424w, https://substackcdn.com/image/fetch/$s_!Bffw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 848w, https://substackcdn.com/image/fetch/$s_!Bffw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 1272w, https://substackcdn.com/image/fetch/$s_!Bffw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bffw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png" width="700" height="370" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:370,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!Bffw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 424w, https://substackcdn.com/image/fetch/$s_!Bffw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 848w, https://substackcdn.com/image/fetch/$s_!Bffw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 1272w, https://substackcdn.com/image/fetch/$s_!Bffw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46a41f92-bfc3-4511-b2da-edc086053a07_700x370.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Memory size over time graph</figcaption></figure></div><p>This graph is crucial because, under normal circumstances, you would expect these lines to maintain a specific range. If your application includes memory-bound endpoints, you might anticipate some spikes. However, based on how you&#8217;ve defined your load test, these lines should normalize once the memory-bound endpoints have completed their tasks. Consequently, if a line continually grows over time without ever decreasing, it&#8217;s a significant sign of a memory leak.</p><h1><strong>Bonus: Simulate memory leak</strong></h1><p>As a bonus section, let&#8217;s simulate a memory leak so we can see how both tools can help us identify it.</p><p>First, let&#8217;s update our Python code so we introduce a memory leak endpoint (something you should never do in production):</p><pre><code># Intentional memory leak: a growing list
leaked_data = []


@app.route("/leak")
def leak_memory():
    """
    Memory leak endpoint.
    """
    leaked_data.append([i for i in range(10000)])
    return jsonify({"status": "Memory leaked!"})</code></pre><p>Every time a request is made to this endpoint, a list of 10,000 integers is created and appended to a global list named <code>leaked_data</code>. Because <code>leaked_data</code> is a global list and is not cleaned up after each request, the memory it uses does not get freed up. This means every time a request is made to the <code>/leak</code> endpoint, more and more memory is used up, simulating a memory leak.</p><p>Let&#8217;s update our <code>locustfile.py</code> to include this endpoint call:</p><pre><code>import random
from locust import HttpUser, task, between


class SimulatedUser(HttpUser):
    wait_time = between(1, 3)

    @task(1)
    def view_users(self):
        self.client.get("/users")

    @task(3)
    def memory_leak(self):
        self.client.get("/leak")

    @task(4)
    def view_user_by_id(self):
        user_id = random.randint(1, 100)
        self.client.get(f"/users/{user_id}")</code></pre><p>Now, we can simply run the application using memray:</p><pre><code>memray run -o result.bin app.py</code></pre><p>And the load test using locust:</p><pre><code>locust -f locustfile.py</code></pre><p>Once you&#8217;ve set up your load test parameters and allowed it to run for some time, you should terminate the <code>memray</code> process. This will generate a <code>result.bin</code> file containing the tracked data. You can then produce a flame graph using this data:</p><pre><code>memray flamegraph result.bin</code></pre><p>Now let&#8217;s review both statistics generated by Locust and Memray:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!f2XY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f2XY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 424w, https://substackcdn.com/image/fetch/$s_!f2XY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 848w, https://substackcdn.com/image/fetch/$s_!f2XY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 1272w, https://substackcdn.com/image/fetch/$s_!f2XY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f2XY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png" width="700" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!f2XY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 424w, https://substackcdn.com/image/fetch/$s_!f2XY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 848w, https://substackcdn.com/image/fetch/$s_!f2XY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 1272w, https://substackcdn.com/image/fetch/$s_!f2XY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffef0aff3-6c3b-4e93-bfe0-8534cb062514_700x400.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Charts from Locust web interface</figcaption></figure></div><p>As the number of our requests increases, we observe that our response times largely remain consistent, barring a single spike. This was expected since the memory leak we introduced does not significantly affect the CPU performance of the application. Thus, we could conclude that our application has <strong>successfully passed</strong> its load test.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GfLx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GfLx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 424w, https://substackcdn.com/image/fetch/$s_!GfLx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 848w, https://substackcdn.com/image/fetch/$s_!GfLx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 1272w, https://substackcdn.com/image/fetch/$s_!GfLx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GfLx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png" width="700" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!GfLx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 424w, https://substackcdn.com/image/fetch/$s_!GfLx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 848w, https://substackcdn.com/image/fetch/$s_!GfLx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 1272w, https://substackcdn.com/image/fetch/$s_!GfLx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26557390-775e-4496-bb8b-25e9ac9dd296_700x400.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Flame graph (Icicles) of our memory leaking application</figcaption></figure></div><p>Here, we can observe more alarming graphs. As explained earlier, the wider the function blocks, the higher the memory allocation. Therefore, it&#8217;s easy to identify that the <code>leaked_data.append(...)</code> block is responsible for the unusual memory consumption.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wIeS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wIeS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 424w, https://substackcdn.com/image/fetch/$s_!wIeS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 848w, https://substackcdn.com/image/fetch/$s_!wIeS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 1272w, https://substackcdn.com/image/fetch/$s_!wIeS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wIeS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png" width="700" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!wIeS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 424w, https://substackcdn.com/image/fetch/$s_!wIeS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 848w, https://substackcdn.com/image/fetch/$s_!wIeS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 1272w, https://substackcdn.com/image/fetch/$s_!wIeS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F49da6783-5229-40a6-ae3b-6e7e86c052fc_700x400.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Memory size over time of our memory leaking application</figcaption></figure></div><p>Examining the memory size over time, we notice that it grows but never shrinks. This indicates a memory leak, as memory is not being released. This issue arises due to the use of a global variable in our example.</p><p>As you can see, memory profiling empowers you to detect issues within your application quickly and efficiently, eliminating the need for long hours of debugging and excessive memory usage logging.</p><h1><strong>Conclusion</strong></h1><p>Ensuring that your application is both efficient and capable of handling high traffic is very important in software development. Through the use of memory profiling and load testing, developers can proactively identify and resolve performance bottlenecks and memory leaks before they affect end users.</p><p>The goal of this guide is to equip you with the tools needed to understand how your application behaves under various loads and to detect unusual memory consumption before it impacts your users. By using load testing and memory profiling, you can identify and address performance issues proactively, ensuring a smoother experience for your customers.</p><p>Feel free to experiment with these tools and adapt them to your specific needs. Happy profiling and testing!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.reversepitch.io/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Dev Whisper! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[How to Handle Long Running Jobs on HTTP]]></title><description><![CDATA[Effective strategy and some best practices for managing long-running HTTP requests]]></description><link>https://www.reversepitch.io/p/how-to-handle-long-running-jobs-on</link><guid isPermaLink="false">https://www.reversepitch.io/p/how-to-handle-long-running-jobs-on</guid><dc:creator><![CDATA[Yuyi Kimura]]></dc:creator><pubDate>Fri, 14 Jun 2024 03:09:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F8ub!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are situations where we need to perform complex or long running operations in our server while exposing it via an API. Those situations will force you to make a choice:</p><ul><li><p>Make the client wait for the response, which make takes more than a minute. (Bad choice)</p></li><li><p>Handle it using a queue and return a task/job resource from which the client can query the progress and eventually the result. (Good choice)</p></li></ul><p>These situations are very common, and turning a long running job into a resource will make your implementation more robust and gives you benefits in both client and server.</p><h2>How can we do this?</h2><p>We accomplish this using an event-based architecture. Basically, our Web API will create a task/job and publish it to an Event Broker. An Event Broker is like an administrator who listen the messages of other services and publish them to specific "spaces" (channels) where other services are waiting for new messages. Take a look to the image below to better understand it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F8ub!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F8ub!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 424w, https://substackcdn.com/image/fetch/$s_!F8ub!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 848w, https://substackcdn.com/image/fetch/$s_!F8ub!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 1272w, https://substackcdn.com/image/fetch/$s_!F8ub!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F8ub!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png" width="1456" height="621" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:621,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Event Broker Diagram.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Event Broker Diagram.png" title="Event Broker Diagram.png" srcset="https://substackcdn.com/image/fetch/$s_!F8ub!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 424w, https://substackcdn.com/image/fetch/$s_!F8ub!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 848w, https://substackcdn.com/image/fetch/$s_!F8ub!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 1272w, https://substackcdn.com/image/fetch/$s_!F8ub!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ea517ac-1edf-4949-8f82-3d46dfde16d8_1500x640.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here we have a very simple (and summarized) diagram in which a client will be requesting the server to apply a cool filter to an image.</p><p>Let's assume this process is long (which may be depending on the filter&#129331;) and making the client wait for it could result in HTTP timeouts or making the site freeze for several seconds.</p><p>In order to tackle this, the Web API will create a Task and send the reference (a unique id) back to the client. Then, the Web API will publish a message to the Event Broker telling the Workers (Image Resizer, Image Processing and Image Upload) that there is a new job for them. These workers can subscribe to channels/topics in the Event Broker, and when a new message arrive to one of those channels it will notify everyone who is subscribed.</p><p>The Workers will start making their job and publishing messages on the Event Broker when they finish (either if the job succeeded or failed). The Web API must be subscribed to these "result" channels and will update the Task status depending on the progress made by the workers. When all Workers finish their jobs successfully, the Task status will change to completed and the URL of the filtered image will be available for the client.</p><p>But wait, how will the client receive the new URL of the filtered image&#129300;? Well, there are several ways to do this.</p><h3>HTTP Polling</h3><p>HTTP Polling is one way to solve this. It consists of repeating an HTTP request over an interval of time. Basically, we will be making a request using the Task reference to the server and if the status is not "Completed" (or "Failed") it will retry again after X seconds.</p><h3>Web Sockets</h3><p>Using Web Sockets the server can send an event to the client when the Task gets completed so the client will get the filtered image when it's ready. This is a better approach in terms of resource consumption but would require adding the complexity of web sockets to your application.</p><p>Either way, our client can now get the filtered image without having to make an HTTP request that takes over a minute to complete&#127881;.</p><h2>Side notes</h2><ul><li><p>When creating the task/job resource, the correct HTTP status code is 202 Accepted. Also, a reference of the task should be sent, like an id or an uri if you are using REST.</p></li><li><p>Cool kids allow the jobs to be deleted from the queue using the reference received on creation. Be a cool kid.</p></li><li><p>Pro kids add an expiration date to tasks, so they don't overwhelm the server. Be a pro kid, even if you are not a cool kid.</p></li></ul><h2>Conclusion</h2><p>There are several patterns and architectures that handle these cases, this is just a personal preference, and I would really like to read your approaches and recommendations in the comment section&#128513;.</p>]]></content:encoded></item></channel></rss>