<?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[Zach Daniel]]></title><description><![CDATA[Kindling for thought.]]></description><link>https://www.zachdaniel.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!F6vw!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03109cde-c295-4f14-8b48-efd49c1634de_500x500.png</url><title>Zach Daniel</title><link>https://www.zachdaniel.dev</link></image><generator>Substack</generator><lastBuildDate>Thu, 30 Apr 2026 07:49:53 GMT</lastBuildDate><atom:link href="https://www.zachdaniel.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Zach Daniel]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[zachdaniel@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[zachdaniel@substack.com]]></itunes:email><itunes:name><![CDATA[Zach Daniel]]></itunes:name></itunes:owner><itunes:author><![CDATA[Zach Daniel]]></itunes:author><googleplay:owner><![CDATA[zachdaniel@substack.com]]></googleplay:owner><googleplay:email><![CDATA[zachdaniel@substack.com]]></googleplay:email><googleplay:author><![CDATA[Zach Daniel]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Software Conjuring]]></title><description><![CDATA[Software engineering is becoming a mystic art]]></description><link>https://www.zachdaniel.dev/p/software-conjuring</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/software-conjuring</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Mon, 16 Feb 2026 02:00:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Vkrr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Still amazed I have to say this, but this was not written by &#8220;AI&#8221;. It&#8217;s directly off the noggin, all organic, 100% meat-made.</p><p>Before the dawn of LLMs, I would often write little bits of software or small apps to make my life easier. Hardly a novel concept, programmers have been doing this for an age. It&#8217;s exhilarating to automate the boring or difficult parts of life! </p><p>Humans can finally extend their reach, their leverage, their <strong>power</strong> out past the bounds of space and time!</p><p>I built my entire career out of sharing my own methodologies of software engineering. I put code and ideas out into the world for free, other people liked them (many did not), and I landed myself a job where I got to focus a vast majority of my time on my passion projects.</p><p>And I can&#8217;t shake the feeling that this really is the end of an era. I built a community and a platform along with an open source framework. Through that community, through the world of open source, I can see that critical mass has been reached.</p><p>Funnily enough, LLMs are only one part of that equation. A big part, sure, but software has been trending easier since its inception. Small teams have been building wildly impressive software for many years now. To me LLMs just feel like the last chapter of a story that has been winding down for a while. We may still have many years ahead of us...but one way or another...</p><div class="pullquote"><p>Software engineering will become software conjuring</p></div><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vkrr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vkrr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!Vkrr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!Vkrr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!Vkrr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vkrr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png" width="380" height="570" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1536,&quot;width&quot;:1024,&quot;resizeWidth&quot;:380,&quot;bytes&quot;:3059810,&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.zachdaniel.dev/i/188093101?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.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_!Vkrr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!Vkrr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!Vkrr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!Vkrr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc63726a6-b7e2-4354-ae16-a898351e9c4d_1024x1536.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the occult literature, conjuring is somehow both technical and magical. Your pentagram must be drawn just right. Your circle of salt mustn&#8217;t be broken. You must say your incantation just so, else you risk the wrath of a paranormal entity. You can&#8217;t give a demon too much information about yourself otherwise it will have power over you. Your instructions must be so clear that they cannot possibly be turned back on you by a malignant entity.</p><p>Starting to sound familiar?</p><div><hr></div><p>I&#8217;ve found myself to be <strong>quite</strong> effective at the use of LLMs to build software, and the latest iterations of Claude and ChatGPT are only enhancing that fact. I am extremely skilled with my own suite of tools that I built <em>for building</em> these kinds of things. Because of that, I can give an LLM very clear instructions about what I want built and how I want it built.</p><p>The thing is that it really doesn&#8217;t feel like engineering any more. I feel instead that I&#8217;ve gotten really good at my spellwork. I&#8217;ve studied the ancient lore of &#8220;functional programming&#8221; and &#8220;abstraction&#8221;. <em><strong>My language of choice is called Elixir for christ&#8217;s sake. </strong></em>I&#8217;ve learned to draw very straight lines on my pentacles (the boundaries I give to the LLM). Place this here, place that there. I know where it will try to make naughty choices and how to head it off before the little machine demon can mess something up.</p><p>I&#8217;m starting to feel like a software conjurer, and honestly I have <em>no idea</em><strong> </strong>how I feel about that.</p>]]></content:encoded></item><item><title><![CDATA[The quiet benefit of open source LLMs]]></title><description><![CDATA[A.K.A Why I don't care about the artificially deflated price of SOTA model API services]]></description><link>https://www.zachdaniel.dev/p/the-quiet-benefit-of-open-source</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/the-quiet-benefit-of-open-source</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Thu, 28 Aug 2025 15:49:51 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7ff7726c-19f4-4b18-a7a5-dbe40a6799a7_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There is a lot of talk about leaning into open source models as a way to mitigate the eventual cranking up of prices from companies like Anthropic, OpenAI and Google. The line of thinking goes something like &#8220;The prices are artificially deflated and therefore you should not make these SOTA models a core part of your workflow, because the rug will eventually be pulled&#8221;.</p><p>There is a small but critical aspect missed in that line of thinking. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Right now, SOTA model API providers are cheaper and easier to use than rolling your own. So we use them. We&#8217;re getting a bunch of free tokens it would be stupid not to. But the fact that for ~$20k I can have all the hardware I need to roll my own LLM stack and &#8220;approximate&#8221; the benefits of what I currently get from Sonnet 4.1 is all that needs to be true for us to have a massive security blanket.</p><p>The cost of using a SOTA model is capped to some function of the time and money it would cost me to set up my own stack. If prices begin to rise, at some point, a $20k down payment for my own state of the art hardware and the time involved in setting up my own ML stack will become &#8220;cheaper&#8221;.</p><p>That side of the equation makes Nvidia just as much money, if not <strong>more</strong> money due to the lack of bulk purchasing, so it will always remain viable at some price point. The OSS models continue to advance on their own independent market and geopolitical forces.</p><p>I&#8217;m not going to waste my time setting up local models and OSS agents. I&#8217;m just going to benefit from the fact that SOTA model API providers margin can never exceed the amount of money it would take me to tell them to fuck off and roll my own.</p><div><hr></div><p><strong>But what about all of the cool features they have that are hard to get out of local and OSS models?</strong></p><p>One other factor here that we&#8217;re seeing emerge is that so many LLM products differentiate themselves on their &#8220;harness&#8221;. i.e system prompts, agentic loops, stitching together disparate models. There are already tons of services that help you approach SOTA model performance with local models by combining different models and approximating similar behavior on weaker hardware.</p><div><hr></div><p>The bottom line is that OpenAI and Anthropic and Gemini are saving you time and money, not providing you a service that you can&#8217;t get via similar means working directly with hardware providers. The moment they aren&#8217;t, you go straight to the source and work directly with Nvidia and the latest open model. Also, buy Nvidia stock &#129335;&#8205;&#9794;&#65039;.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! 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[Elixir Misconceptions #1]]></title><description><![CDATA[Don't "let it crash". Let it heal.]]></description><link>https://www.zachdaniel.dev/p/elixir-misconceptions-1</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/elixir-misconceptions-1</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Mon, 28 Jul 2025 16:56:15 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/16f639fc-6904-42be-a38d-32c5e99e5815_1024x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is the first of a series on misconceptions about Elixir. These are my opinions. I hope they spark discussion and that maybe we all learn things as a result.</p><div><hr></div><p>A note to the Elixir programmers who commonly say &#8220;let it crash&#8221;: This phrase gives outsiders and newcomers the wrong idea, and encourages bad habits for those who misinterpret it. If I had my way, we would stop saying it.</p><div class="pullquote"><p>Let it crash.</p></div><p>Elixir runs on the BEAM VM. If you&#8217;re familiar, skip to the next paragraph. Otherwise, some necessary context is that on the BEAM, all code is executed in a &#8220;process&#8221;. This can be thought of kind of like a green thread. Each process is a lightweight, share-nothing unit of concurrency. Processes communicate via message passing. When processes encounter an unhandled error, the process exits. We use supervisors (which are themselves supervised typically), to then restart any given crashed process.</p><p>When people say &#8220;let it crash&#8221;, they are referring to the fact that practically any exited process in your application will be subsequently restarted. Because of this, you can often be much less defensive around unexpected errors. You will see far fewer try/rescue, or matching on error states in Elixir code.</p><div class="pullquote"><p>The &#8220;it&#8221; in &#8220;let it crash&#8221; to an Elixir programmer is <strong>a process. </strong>Not your application. </p><p>In practice, an Elixir application almost <strong>never</strong> crashes, even in conditions that would hard-quit in any other system. </p></div><p>For those without the context of building Elixir applications, &#8220;let it crash&#8221; gives the impression of &#8220;jank&#8221;, of non-elegant code that does not consider user experience or possible failure states. A panic or crash in most languages is a catastrophic event, to be avoided at all costs.</p><p>Even for Elixir developers with experience, &#8220;let it crash&#8221; as a practice loses enough nuance so as to be reductive, and I&#8217;ve seen it actively impact the quality of code that comes across my desk.</p><p>First, we&#8217;ll talk about why you shouldn&#8217;t &#8220;let it crash&#8221;, and then we&#8217;ll talk about what you should do instead.</p><h3>Processes are tied to real things</h3><p>Open a socket connection, receiving or sending an HTTP request, opening a file, connecting to a database: all of these things are typically backed by a process. 99% of the time, that process is linked to the process that asked for that to happen. The most straightforward example of this is in the context of a web server communicating over a web socket, and if you&#8217;re familiar with it, Phoenix LiveView.</p><p>Lets imagine that we embrace the &#8220;let it crash&#8221; philosophy to the bone, and we write some code like this, handling a web socket message:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BrZc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BrZc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 424w, https://substackcdn.com/image/fetch/$s_!BrZc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 848w, https://substackcdn.com/image/fetch/$s_!BrZc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!BrZc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BrZc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png" width="1456" height="727" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:727,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:183691,&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.zachdaniel.dev/i/169461266?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.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_!BrZc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 424w, https://substackcdn.com/image/fetch/$s_!BrZc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 848w, https://substackcdn.com/image/fetch/$s_!BrZc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 1272w, https://substackcdn.com/image/fetch/$s_!BrZc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F492c06cc-591f-47cf-a7ce-64319703e59a_2868x1432.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This code will crash the process in the following scenarios:</p><ul><li><p>the pattern match on the event name fails `&#8221;import_data&#8221;`</p></li><li><p>the pattern match on the input params fails (there is no &#8220;data&#8221; key)</p></li><li><p>`data` is not a list (technically, an enumerable of some kind)</p></li><li><p>Any given item in data fails to be created or raises an error</p></li></ul><p>In some cases, especially &#8220;invalid messages that should not be producible&#8221;, crashing is a <em>good</em> thing. For the first two, and maybe three things in the list above, hitting those cases implies a bug in your front end likely. Someone sending your process messages it was never designed to handle. Crashing may be the desired behavior.</p><p><strong>BUT: </strong>There is a user on the other end of this. In the case of LiveView, the web socket is driving at least some part of their experience. Establishing a websocket takes time. What will the user experience be? Will they see a flash message about something going wrong? Will some of their UI state reset? None of these things are really acceptable. This pattern is all over, not just tied to LiveView. Do you want to close whatever file/database connection you have every time anything goes wrong? Or release some other expensive resource? What if you encounter thousands errors in quick succession? Will restarting be expensive?</p><h3>Representing Failed States</h3><p>Intentionally crashing on any possible error also means that you are not <strong>able to represent errored states to your users</strong>. For our above example, something like this might make more sense:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y0KV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y0KV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 424w, https://substackcdn.com/image/fetch/$s_!y0KV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 848w, https://substackcdn.com/image/fetch/$s_!y0KV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 1272w, https://substackcdn.com/image/fetch/$s_!y0KV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y0KV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png" width="1456" height="1670" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1670,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:515485,&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.zachdaniel.dev/i/169461266?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.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_!y0KV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 424w, https://substackcdn.com/image/fetch/$s_!y0KV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 848w, https://substackcdn.com/image/fetch/$s_!y0KV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 1272w, https://substackcdn.com/image/fetch/$s_!y0KV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F840c1461-78e4-4308-923f-9675d67b9d8d_3048x3496.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In this example, instead of just crashing and seeing some generic error, the user is given actionable information about what went wrong. We have represented the failed state.</p><p>With that said, in practice we take a middle-way. Specifically, in fully unexpected scenarios that cannot be remediated, like getting a malformed &#8220;import_data&#8221; command, it is often <strong>preferable</strong> to crash. We crash because the process is now in an unrecoverable bad state, and we don&#8217;t know how it got there. In this case, we want to remount the component into a good state. You still have to consider the UX of this scenario, and design your pages to gracefully remount.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4TMF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4TMF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 424w, https://substackcdn.com/image/fetch/$s_!4TMF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 848w, https://substackcdn.com/image/fetch/$s_!4TMF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 1272w, https://substackcdn.com/image/fetch/$s_!4TMF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4TMF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png" width="1456" height="1239" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1239,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:394237,&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.zachdaniel.dev/i/169461266?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.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_!4TMF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 424w, https://substackcdn.com/image/fetch/$s_!4TMF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 848w, https://substackcdn.com/image/fetch/$s_!4TMF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 1272w, https://substackcdn.com/image/fetch/$s_!4TMF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F377a6d3b-8fb0-4ac3-8c67-dc6a54778227_3160x2688.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here we crash on unknown or garbled messages/input, but present validation errors to the user.</p><p>So, we&#8217;ve established that there are consequences to crashing, and that we should not default to the overly reductive &#8220;let it crash&#8221; mentality here. Does that mean that the &#8220;let it crash&#8221; people entirely wrong? Only kind of.</p><h2>Let it heal</h2><p>Remember when we talked about supervisors and restarting etc? The operative part of these things is not that processes are designed to crash, it is that they are designed to <strong>start.</strong> As in, when your application first boots up, you have to start up your process tree, and supervisors are at that point embedded with the information required to start a process if it crashes. </p><p>What this means for Elixir programmers is that we <strong>can</strong> let it crash when things are unrecoverable. What this does <strong>not</strong> mean for Elixir programmers is that all errors anywhere inside of a process should cause a crash.</p><div><hr></div><p>The real magic of the BEAM is that for any given piece of code running in Elixir, there is another, higher level piece of code that knows how to handle errors that cannot be locally handled by that code. </p><p>You can&#8217;t write code that isn&#8217;t aware of the fact that something might go catastrophically wrong, because all of your code implicitly has a &#8220;how do I initialize myself&#8221; step that must be able to gather any requirements and &#8220;set the stage&#8221; for itself. </p><p>There is often still work that goes into designing these structures, but we are getting something for free or close-to-free that takes a crack team of experts or specialized frameworks to achieve in other languages.</p><p>While &#8220;let it heal&#8221; may not be as catchy, I think it better captures the BEAM&#8217;s true superpower: not that our processes can die, but that they can always come back to life.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! 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[Usage Rules: Leveling the Playing Field for AI-Assisted Development]]></title><description><![CDATA[How the OSS community can democratize LLM context management]]></description><link>https://www.zachdaniel.dev/p/usage-rules-leveling-the-playing</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/usage-rules-leveling-the-playing</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Fri, 18 Jul 2025 16:11:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!KKGy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As an OSS maintainer I&#8217;m confronted with a new truth daily. A huge amount of people are using LLMs, and for the most part they are using them &#8220;badly&#8221;. The amount of hallucinations I&#8217;ve been asked questions about, and &#8220;AI slop&#8221; I&#8217;ve had to deal with is astronomical. We have a new paradigm available to us in software engineering, whether we like it or not.</p><p>In some ways, it feels like we&#8217;re living in the year 3000, but in other ways it&#8217;s like the stone ages. There are people succeeding past their wildest expectations with agentic tooling, and there are people trying and failing to find any success with these tools. OSS is about leveling the playing field, so <strong>let&#8217;s level it</strong>.</p><div><hr></div><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;8b0a6eef-1ee5-46e3-8ca8-43c9eb5f16ca&quot;,&quot;duration&quot;:null}"></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Right now, we have the ability to automate and share the vast majority of agentic development tools, but there is one <em>major</em> missing piece. Folks are using things like claude code, codex, gemini etc. which roll forward as new tools and best practices arise. We also use things like MCP servers to distribute tools. While <a href="http://tidewave.ai">some MCP servers</a> are game changing, I have lots of gripes w/ MCP, but thats a topic for later. The underlying software and libraries that agents work with is also distributed via package managers. All of it can be iterated on and everyone can update to benefit.</p><p>However, the most crucial aspect of agentic development is currently left for everyone to figure out on their own! We can give our agents access to tools which they can use to populate their context window (i.e prompt), but the prompt that we actually start with affects everything down the line. </p><p>Whether or not you realize it, all of these agentic coding tools have their own, typically hefty, system prompt designed to make an agent better at operating within the framework and tools that they give it. Most folks realize that system prompts are both impossible to protect and also not a realistic moat, so <a href="https://docs.anthropic.com/en/release-notes/system-prompts">many</a> <a href="https://github.com/elder-plinius/Google-Gemini-System-Prompt/blob/main/full_prompt.md">are</a> <a href="https://zed.dev/leaked-prompts">published</a>. However, as soon as you type into the chat box, you&#8217;re doing what many call &#8220;prompting&#8221;, but what I think of as &#8220;context management&#8221;.</p><h3>Context  Management</h3><p>Ultimately, LLMs take some context, and produce some subsequent text. Its wild when you boil it down, but that is how it all works. Some special JSON text response formats indicate tool calls. &#8220;thinking&#8221; is just indicated by wrapping some text in &lt;thinking&gt; tags. Success with LLMs is figuring out this weird, difficult to predict and &#8220;squishy&#8221; concept of context management. While complex in practice, it really boils down to &#8220;what text in will produce desirable text out&#8221;.</p><p>While the concept of &#8220;vibe coding&#8221; is honestly ridiculous, it does nail one fascinating aspect of this whole thing, which is that context management, in my experience, really does involve <strong>intuition</strong>. Its not realistic to think about the mathematics or the vectors etc. It <strong>feels </strong>more like a <em>soft skill</em>, like a <em>people problem, </em>than a technical one.</p><p>As an OSS software engineer, a lot of my job is to lift up the community and engineers around me, and what I see currently is that they <em>are being left behind</em>. I&#8217;m not talking about LLM skeptics. I&#8217;m not looking to shove LLMs down anyone&#8217;s throat. I&#8217;m talking about less experienced engineers, or engineers who don&#8217;t have the time to discover and hone this new skill. They feel that there is some new state of the art out there, but that it is inaccessible to them because they haven&#8217;t figured out how to wield it.</p><h3> Usage Rules - Breaking down the silos</h3><p>The solution for this is frankly simple, and leans into the patterns we already have in place for software engineering. I&#8217;m calling it &#8220;Usage Rules&#8221;. The concept is simple, distributed with any given software package or tool, there is a `usage-rules.md` or and/or a `usage-rules/` folder with markdown files inside of it. These usage rules are <em>not</em> general documentation. It isn&#8217;t `llms.txt`. Instead, it is &#8220;what the authors of the tool think you should put into your agent&#8217;s context window to successfully use their package&#8221;.</p><p>For large frameworks, usage rules might be <a href="https://github.com/ash-project/ash/blob/f24a77e68b6a08ebafe13bc98c362f049af34b67/usage-rules.md#L4">really big</a>. For smaller/simpler tools, it might just be a few lines. For end users, even just a few lines can make a huge difference. Then we use tooling to synchronize those usage rules into the appropriate places (i.e `AGENTS.md`, `CLAUDE.md`) on the user&#8217;s file system, in such a way that it can be kept up to date over time. I&#8217;ve implemented this tooling for the Elixir ecosystem and I&#8217;d <strong>strongly encourage</strong> other languages, frameworks and library developers to follow suit, using the same file naming conventions.</p><p>In practice, we use it like so:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KKGy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KKGy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 424w, https://substackcdn.com/image/fetch/$s_!KKGy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 848w, https://substackcdn.com/image/fetch/$s_!KKGy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 1272w, https://substackcdn.com/image/fetch/$s_!KKGy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KKGy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png" width="1456" height="1281" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1281,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:220340,&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.zachdaniel.dev/i/168645916?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.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_!KKGy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 424w, https://substackcdn.com/image/fetch/$s_!KKGy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 848w, https://substackcdn.com/image/fetch/$s_!KKGy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 1272w, https://substackcdn.com/image/fetch/$s_!KKGy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18960638-77ff-45d5-ab37-99bc59a1dfdd_2136x1880.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><br>This synchronizes some builtin rules for Elixir &amp; OTP, as well as any usage rules from your direct dependencies. There are <strong>lots </strong>of different ways to use usage rules. Perhaps you want some inlined into your AGENTS.md and some to link to the dependencies folder. Or perhaps you want to copy <strong>all</strong> rules into a folder and link there. Or perhaps you want to use CLAUDE.md style `@file/link`s. All available as options to `usage_rules.sync`!</p><p>All reports show effectively a <strong>night and day</strong> difference in folks&#8217; experience with agents. The more off-the-beaten-path, or the more recently released what you&#8217;re working with is, the more effective thse tools are. Software changes a lot more often than LLM&#8217;s reindex the internet, so you have this problem even if you are using the most popular tech that exists.</p><p>On a fresh project, this yields a <a href="https://gist.github.com/zachdaniel/8ac5b60bac396b8e9797a9db3bd60f02">pre-loaded and useful AGENTS.md</a></p><h3>What are the benefits?</h3><p>There are numerous benefits, but lets go through some of the major ones:</p><ul><li><p>End users can get &#8220;free&#8221; context that helps their agents succeed with the tools they use.</p></li><li><p>These can be collaborated on. When agents keep making the same mistakes, or not choosing the correct tools for the job, <a href="https://github.com/ash-project/ash/pull/2100/files">you can make a PR to the usage-rules.md</a>!</p></li><li><p>usage rules are updated with the project. When you upgrade your dependencies, simply re-sync your usage rules, and your agents are using the latest features, no matter when the last knowledge cut-off date is.</p></li></ul><h2>Taking it even further for Elixir</h2><p>The Elixir usage_rules package provides tools that allow agents to be successful with no need for additional MCP servers. This is another critical component to making this stuff easy to use and accessible to everyone. We distribute two tasks, `mix usage_rules.search_docs` and `mix usage_rules.docs`, which allow the agent to search Elixir&#8217;s centralized documentation repository across <strong>all packages you are using in your app</strong>(or for specific packages). The built-in usage rules instruct the agent on how to run these tasks effectively.</p><p>Instead of making repeated shots in the dark, agents now have a fool-proof method of discovering their mistakes and what they don&#8217;t know! No need for an MCP server or any particular agentic tool. They can all call bash commands.</p><h2>Rising Tides</h2><p>I hope that these patterns and this type of tooling catches on, because rising tides raise all ships. We&#8217;ve been doing this for decades in OSS and new paradigms don&#8217;t change that prerogative.</p><p>To learn more, or to get started using it, see our docs at <a href="http://hexdocs.pm/usage_rules">hexdocs.pm/usage_rules</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! 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[My LLM workflow & tools | June 06, 2025]]></title><description><![CDATA[I've been asked to share, and so I shall.]]></description><link>https://www.zachdaniel.dev/p/my-llm-workflow-and-tools-june-06</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/my-llm-workflow-and-tools-june-06</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Wed, 11 Jun 2025 17:43:55 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%2F03109cde-c295-4f14-8b48-efd49c1634de_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I included the date because this stuff changes so fast it will be different tomorrow I&#8217;m sure.</p><p>I&#8217;m just going to dive in. Lets start with some guidelines</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! 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><h1>Guidelines </h1><h2>Pay attention</h2><p>Step 1 is to realize that this stuff changes so ridiculously fast that you&#8217;re out of date the moment you use some new tool or pattern. There are two things to keep in mind:</p><h3>Read the news</h3><p>Stay up to date, especially with provider updates like Anthropic,  Open AI, Gemini etc. They are playing tennis with who has the best coding model at this point, but for me Claude 4 has blown everything else out of the water currently.</p><p>For example: <a href="https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/claude-4-best-practices">Claude 4 Best Practices</a></p><h3>Stop reading the news</h3><p>Don&#8217;t forget we&#8217;re here to get shit done. Spend some time refining your setup, keeping up with the world, sure. But don&#8217;t forget to act. A big part of working with LLMs is this weird new prompting/chat soft-skill. You have to hone it and refine it.</p><h2>Don&#8217;t test the machine</h2><p>I often did this myself starting out, which is shoving some half-assed &#8220;fix X bug&#8221; prompt at Claude to see if it would do what I wanted it to do. Protip: it&#8217;s not a person. It's a text machine, a word cannon, that takes text and makes text. We&#8217;re just learning how to use it in all these fancy ways. If you have a thought about things like:</p><ul><li><p>where it should probably look to find something</p></li><li><p>what the root cause of the bug is</p></li><li><p>an edge case it should consider</p></li></ul><p><strong>TELL it that stuff. </strong>Occasionally when working on tools for other developers to enhance their experience with LLMs I&#8217;ll try and prompt it like a doorknob, but when I&#8217;m actually using it to get shit done, it gets as much info as I can feed it.</p><h2>Learn when not to use it</h2><p>You&#8217;re going to have to build up instincts around when you have the kind of problem an LLM will help you with. No one can really do this for you, you just have to try it and see. It gets easier over time.  </p><h1>Tools</h1><h2>Zed</h2><p>I personally much prefer zed over Claude Code, which is the other contender here. Their UI is excellent and has a whole bunch of whistles and bells that you&#8217;ll appreciate more once you figure things out. I still use Claude <strong>models</strong>, but I don&#8217;t use <strong>Claude</strong> <strong>Code</strong>.</p><h2>Zed Pro</h2><p>I don&#8217;t know how long this will last, but Zed&#8217;s pro plan gets past Anthropics rate limits. It costs quite a bit once you get past your allotted prompts. Personally, I value my time at a ridiculous premium, $500/mo is chump change for something that can make me 20-30% more effective. No hard numbers on how much more effective it is making me, but the potential is there. Some days it wastes more time than it saves, and sometimes it saves me 6 hours in one fell swoop. I&#8217;m learning to optimize for those latter cases.</p><h2> MCP Servers</h2><p>Personally, the only MCP servers I care to use currently are the <a href="https://hexdocs.pm/ash_ai">Ash AI dev MCP server</a> and <a href="http://tidewave.ai">Tidewave</a>. Why do I need a GitHub MCP server when it can use `gh`? Besides, most of the time I don&#8217;t want it screwing around with that stuff. How I conduct myself on the internet is personal, not something I&#8217;m interested in delegating to a machine.</p><h1>Rules Files/Context</h1><h3>Global Rules</h3><p>I have two rules files that apply 100% of the time. You should have some too. They aren&#8217;t amazing, but they are, so far, getting the job done. The way that you apply these depends on what you&#8217;re using. Claude expects `CLAUDE.md`. Other things AFAIK are looking for `AGENTS.md`. In zed you manage them in a rules GUI, but it also looks for `AGENTS.md` too.</p><p><a href="https://gist.github.com/zachdaniel/5c3b2da7251f824c802c54e7bab0b3b9">non-negotiables.md</a></p><p><a href="https://gist.github.com/zachdaniel/c06f005f222c63046e01db7b5e2df534">guidelines.md</a></p><h3>Usage Rules</h3><p>Crowdsource your rules. Teach your agent where to find rules on how to use stuff (i.e docs). In <a href="http://elixir-lang.org">Elixir</a>, and with <a href="http://ash-hq.org">Ash Framework</a>, we&#8217;re working on how this can work, and we&#8217;re pushing a pattern called <a href="https://hexdocs.pm/usage_rules">usage-rules.md</a>. I can run one command to create &#8220;breacrumbs&#8221; telling agents where to look for the rules of packages that I want it to use.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pAL0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pAL0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 424w, https://substackcdn.com/image/fetch/$s_!pAL0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 848w, https://substackcdn.com/image/fetch/$s_!pAL0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 1272w, https://substackcdn.com/image/fetch/$s_!pAL0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pAL0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png" width="1456" height="689" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:689,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:78148,&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.zachdaniel.dev/i/165721789?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.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_!pAL0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 424w, https://substackcdn.com/image/fetch/$s_!pAL0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 848w, https://substackcdn.com/image/fetch/$s_!pAL0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 1272w, https://substackcdn.com/image/fetch/$s_!pAL0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87543020-dd02-47e7-a9b4-5a29627fba51_2080x984.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Situational Rules</h3><p>In Claude Code, these are done via <a href="https://docs.anthropic.com/en/docs/claude-code/tutorials#create-project-specific-commands">slash commands</a>. With Zed, it&#8217;s under the agent three-dots button in the top right. Click on rules. You can select which rules always apply by marking them as default rules. Then, to use them, you type `@rule` and it will give you an autocomplete of your rules list.</p><p>I have three situational rules files currently, which map to workflows that I want the LLM to follow depending on what we&#8217;re doing.</p><p><a href="https://gist.github.com/zachdaniel/59fd227750348a5b8d14fc54c1934533">feature-workflow.md</a></p><p><a href="https://gist.github.com/zachdaniel/ceeb3b7abf8be6aa91166c17e33bde05">fix-workflow.md</a></p><p><a href="https://gist.github.com/zachdaniel/acca7dc082b9b0564686091a72355ddc">task-workflow.md</a></p><p>Which brings us to:</p><h2>Prompting</h2><p>At the end of the day, all your rules just get put into the prompt/context that you send to the LLM. Some things to keep in mind:</p><h3> LLMs do not KNOW anything</h3><p>Make your LLM do research, and load that research up into the context window, token use be damned. Make it very clear that they are to research heavily.</p><h3>Collaborate on  a plan file</h3><p>Have it build and collaborate on plan documents. When it&#8217;s made a plan, open it up, add a bunch of todo comments to the plan, and tell it to review (or just tell it what to change). This planning step is crucial because what you&#8217;re <strong>actually</strong> doing, is collaborating with the LLM on a <strong>better prompt</strong> for the LLM. The plan document performs so many useful functions that it is hard to count.</p><ul><li><p>Keeps the LLM on track</p></li><li><p>The plan can be resumed at any time</p></li><li><p>The plan can even be committed or shared as a trimmed down version of what you and the LLM did. Will humans read it? Probably not. If only we had a magic machine that could do a whole bunch of cool shit if given a bunch of relevant text&#8230;</p></li><li><p>Acts as a clarified feedback mechanism for the work the agent is doing.</p></li><li><p>When you have it load up things like &#8220;risks&#8221; and &#8220;unknowns&#8221; into the plan, you&#8217;re priming it to avoid mistakes but also you&#8217;re informing your *own* engineering process.</p></li></ul><h3>Do &lt;this&gt; like &lt;that&gt;</h3><p>LLMs are amazing at &#8220;translation&#8221; and &#8220;reformatting&#8221;. So if you can point it to some code that is &#8220;kind of&#8221; like what you want right now, you&#8217;re going to get wildly better results.</p><h3>Iterate on your rules</h3><p>When you notice that the agent is doing something you don&#8217;t like often, or is repeatedly not doing something you want it do, edit your rules file. Bonus points for having the agent propose changes to the rules for you. Claude Code is good for this, zed is not since the rules don&#8217;t live in the codebase or in a place that its easy to point the agent at as far as I can tell.</p><h1>Use Ash Framework</h1><p>This is just a plug for my other tools, not really relevant to the above. If you&#8217;re interested in my other work, see:</p><ul><li><p><a href="http://ash-hq.org">Ash Framework</a></p></li><li><p><a href="https://pragprog.com/titles/ldash/ash-framework/">The Ash Framework Book</a></p></li><li><p>The <a href="https://www.youtube.com/watch?v=PSrzruaby1M">new Ash AI package</a> for building AI enabled applications</p></li></ul><p></p><h2>Feedback</h2><p>Like these ideas? Let me know?</p><p>Have some constructive feedback or ideas? Lets chat &#10084;&#65039;</p><p>Hate everything about this post? Make sure to smash that like and subscribe.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! 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[LLMs & Elixir: Windfall or Deathblow?]]></title><description><![CDATA[How the Elixir community can survive &#8212; and thrive &#8212; in an age of LLMs.]]></description><link>https://www.zachdaniel.dev/p/llms-and-elixir-windfall-or-deathblow</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/llms-and-elixir-windfall-or-deathblow</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Sun, 01 Jun 2025 16:25:25 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%2F03109cde-c295-4f14-8b48-efd49c1634de_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Will &#8220;AI&#8221; take our jobs? Will it <a href="https://en.wikipedia.org/wiki/Enshittification">enshittify</a> our profession, transitioning us into managers for stupid robots? Does it dream of electric sheep? Today I&#8217;d like to introduce a new fear and, perhaps, throw you a rope with which to pull yourself out. </p><p>If LLMs turn out to be a fad and you&#8217;re reading this after they jump the shark, please accept this article as a historical artifact from a time when we entertained the idea that fancy autocomplete might eat the world.</p><p>Aside, for those who don&#8217;t know what <a href="http://elixir-lang.org">Elixir</a> is: it&#8217;s the <a href="https://discord.com/blog/how-discord-handles-push-request-bursts-of-over-a-million-per-minute-with-elixirs-genstage">best</a> <a href="https://elixir-lang.org/blog/2023/03/09/embedded-and-cloud-elixir-at-sparkmeter/">general</a> <a href="https://underjord.io/elixir-as-competitive-advantage.html?utm_source=chatgpt.com">purpose</a> <a href="https://medium.com/coryodaniel/from-erverless-to-elixir-48752db4d7bc">language</a> <a href="https://moz.com/devblog/moz-analytics-db-free">in</a> <a href="https://www.zachdaniel.dev/p/serialization-is-the-secret?r=f3smb&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=false">the</a> <a href="https://curiosum.com/blog/elixir-programming-language-guide#:~:text=What%20is%20Elixir%20and%20why,%2C%20and%20fault%2Dtolerant%20applications.">world</a> <a href="https://paraxial.io/blog/elixir-savings">and</a> <a href="https://dockyard.com/blog/2025/04/24/elixir-success-story-clarus-r-d-rebuilds-smarter?utm_source=chatgpt.com">if</a> <a href="https://elixir-lang.org/blog/2021/11/10/embracing-open-data-with-elixir-at-the-ministry-of-ecological-transition-in-france/">you</a> <a href="https://elixir-lang.org/blog/2025/03/25/cyanview-elixir-case/">haven&#8217;t</a> <a href="https://www.thegreatcodeadventure.com/an-elixir-adoption-success-story/?utm_source=chatgpt.com">heard</a> <a href="https://www.erlang-solutions.com/blog/why-elixir-is-the-programming-language-you-should-learn-in-2024/">of</a> <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ">it</a> <a href="https://elixir-lang.org/blog/2025/01/21/remote-elixir-case/?utm_source=chatgpt.com">wake</a> <a href="https://elixir-lang.org/blog/2020/11/17/real-time-collaboration-with-elixir-at-slab/">up</a> <a href="https://www.monterail.com/blog/famous-companies-using-elixir?utm_source=chatgpt.com">and</a> <a href="https://elixir-lang.org/blog/2021/04/02/marketing-and-sales-intelligence-with-elixir-at-pepsico/">smell</a> <a href="https://alembic.com.au/case-studies/transforming-healthcare-communication-with-elixir-and-ash-framework">the</a> <a href="http://ash-hq.org">bacon</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! 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><h2>Will &#8220;AI&#8221; force a convergence towards the tools it  &#8220;knows&#8221; best?</h2><p>The argument goes like so: Now that you have a bunch of folks who are &#8220;vibe coding&#8221;, they will just do whatever ChatGPT or Claude tell them to do. They will also be evaluating things almost solely against &#8220;how well did my &#8216;AI&#8217; do with it&#8221; for making decisions going forward. For Elixir, this sounds like bad news bears. Here is a portion of a very long-winded response from ChatGPT when I asked it how I could &#8220;build a website like Amazon&#8221;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4-Cf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4-Cf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 424w, https://substackcdn.com/image/fetch/$s_!4-Cf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 848w, https://substackcdn.com/image/fetch/$s_!4-Cf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 1272w, https://substackcdn.com/image/fetch/$s_!4-Cf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4-Cf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png" width="510" height="586.7179487179487" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1346,&quot;width&quot;:1170,&quot;resizeWidth&quot;:510,&quot;bytes&quot;:224964,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.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_!4-Cf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 424w, https://substackcdn.com/image/fetch/$s_!4-Cf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 848w, https://substackcdn.com/image/fetch/$s_!4-Cf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 1272w, https://substackcdn.com/image/fetch/$s_!4-Cf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc118a7-036d-4a73-a1bb-cf677f00cd1a_1170x1346.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Oh no! I in my ultimate wisdom know that this is nowhere close to the best stack for the job. But the noobs won&#8217;t know that at all! Let&#8217;s say instead they&#8217;ve heard of Elixir on a blog post, or they saw this article topping the hacker news charts &#129310; (hi mom!). </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JBuI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JBuI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 424w, https://substackcdn.com/image/fetch/$s_!JBuI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 848w, https://substackcdn.com/image/fetch/$s_!JBuI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 1272w, https://substackcdn.com/image/fetch/$s_!JBuI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JBuI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png" width="1318" height="198" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:198,&quot;width&quot;:1318,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29090,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.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_!JBuI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 424w, https://substackcdn.com/image/fetch/$s_!JBuI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 848w, https://substackcdn.com/image/fetch/$s_!JBuI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 1272w, https://substackcdn.com/image/fetch/$s_!JBuI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc936c91f-a0d4-4d4d-8c4d-00ef464c2a08_1318x198.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WREn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WREn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 424w, https://substackcdn.com/image/fetch/$s_!WREn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 848w, https://substackcdn.com/image/fetch/$s_!WREn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 1272w, https://substackcdn.com/image/fetch/$s_!WREn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WREn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png" width="1456" height="287" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:287,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:104325,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.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_!WREn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 424w, https://substackcdn.com/image/fetch/$s_!WREn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 848w, https://substackcdn.com/image/fetch/$s_!WREn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 1272w, https://substackcdn.com/image/fetch/$s_!WREn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe3a2b6e-9eac-490b-b270-ac1830dfda98_1854x366.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I&#8217;m in this unique situation where time-to-market happens to matter. Also what do you mean &#8220;learning curve&#8221;, you&#8217;re supposed to do the learning for me. Thanks Chat, you really helped me dodge a bullet here, guess I&#8217;ll stick with Node &amp; Next.js, thanks! &#129392;</p><h2>Lets not beat a dead straw man</h2><p>Mixing metaphors like a boss. While I&#8217;m sure the above scenario will play out countless times, at the end of the day this <strong>isn&#8217;t new</strong>. Theoretically this all goes one of two ways.</p><ol><li><p>&#8220;AI&#8221; is able to overcome the fundamental issues with any tool, thus equalizing effectively all programming languages.</p></li><li><p>Vibe coders &amp; new programmers working with LLMs hit the same walls that drove Elixir to exist in the first place.</p></li></ol><p>In my opinion, both of these realities are &#8220;good news&#8221; in a way. In scenario 1, we&#8217;ve got magical mystery robots and they&#8217;ll just create the one programming language to rule them all and now we all have infinite automation in our pockets. Let&#8217;s talk about scenario 2, the one I find far more likely.</p><h2>Hitting Walls</h2><p>It&#8217;s no surprise that these things will mirror popular opinion. We can finagle our way there. This is a fresh prompt.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jtzc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jtzc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 424w, https://substackcdn.com/image/fetch/$s_!jtzc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 848w, https://substackcdn.com/image/fetch/$s_!jtzc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 1272w, https://substackcdn.com/image/fetch/$s_!jtzc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jtzc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png" width="1286" height="204" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:204,&quot;width&quot;:1286,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:115220,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.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_!jtzc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 424w, https://substackcdn.com/image/fetch/$s_!jtzc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 848w, https://substackcdn.com/image/fetch/$s_!jtzc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 1272w, https://substackcdn.com/image/fetch/$s_!jtzc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc659d9be-a56c-4b5f-8ff1-67278bee1ee7_1286x204.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>After giving me a bunch of sensible recommendations like using a CDN, horizontally scaling, using background jobs, migrating from Vercel to ECS, and scrolling past the recommendations to rewrite in Go and Rust, we finally found what we were looking for &#129401;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p9Z9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p9Z9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 424w, https://substackcdn.com/image/fetch/$s_!p9Z9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 848w, https://substackcdn.com/image/fetch/$s_!p9Z9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 1272w, https://substackcdn.com/image/fetch/$s_!p9Z9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p9Z9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png" width="880" height="374" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:374,&quot;width&quot;:880,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:68622,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.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_!p9Z9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 424w, https://substackcdn.com/image/fetch/$s_!p9Z9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 848w, https://substackcdn.com/image/fetch/$s_!p9Z9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 1272w, https://substackcdn.com/image/fetch/$s_!p9Z9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6340b5db-0b37-42e8-a7c8-41ce1aebd703_880x374.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This brings us to a crucial realization: if LLMs can successfully guide someone toward Elixir when the use case demands it, then perhaps the real challenge isn't LLM bias toward mainstream tools - it's making sure LLMs can work effectively with our tools to enable developers to make that choice.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0MQL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0MQL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 424w, https://substackcdn.com/image/fetch/$s_!0MQL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 848w, https://substackcdn.com/image/fetch/$s_!0MQL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 1272w, https://substackcdn.com/image/fetch/$s_!0MQL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0MQL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png" width="958" height="140" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:140,&quot;width&quot;:958,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17370,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.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_!0MQL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 424w, https://substackcdn.com/image/fetch/$s_!0MQL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 848w, https://substackcdn.com/image/fetch/$s_!0MQL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 1272w, https://substackcdn.com/image/fetch/$s_!0MQL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3af91a5c-7911-4b0c-8898-50eccae49074_958x140.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Alright, I&#8217;m up and running. Not sure how this would cost someone $10k on Vercel but I&#8217;m sure someone could find a way.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g1fo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g1fo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 424w, https://substackcdn.com/image/fetch/$s_!g1fo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 848w, https://substackcdn.com/image/fetch/$s_!g1fo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 1272w, https://substackcdn.com/image/fetch/$s_!g1fo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g1fo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png" width="1456" height="625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:166315,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.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_!g1fo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 424w, https://substackcdn.com/image/fetch/$s_!g1fo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 848w, https://substackcdn.com/image/fetch/$s_!g1fo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 1272w, https://substackcdn.com/image/fetch/$s_!g1fo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16a85c36-18dd-4096-ba11-131ff5285276_1802x774.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So let's test this theory. If I take Claude's advice and decide to explore Elixir, how well can it help me actually build something?</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!f2lw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f2lw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 424w, https://substackcdn.com/image/fetch/$s_!f2lw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 848w, https://substackcdn.com/image/fetch/$s_!f2lw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 1272w, https://substackcdn.com/image/fetch/$s_!f2lw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f2lw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png" width="960" height="128" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:128,&quot;width&quot;:960,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15759,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.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_!f2lw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 424w, https://substackcdn.com/image/fetch/$s_!f2lw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 848w, https://substackcdn.com/image/fetch/$s_!f2lw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 1272w, https://substackcdn.com/image/fetch/$s_!f2lw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc8be0157-ed49-4c12-89a3-e687ff8cdde2_960x128.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Not only does it work, but it does it effectively the same way that I personally would have done it if given the same task.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-faw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-faw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 424w, https://substackcdn.com/image/fetch/$s_!-faw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 848w, https://substackcdn.com/image/fetch/$s_!-faw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 1272w, https://substackcdn.com/image/fetch/$s_!-faw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-faw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png" width="890" height="662" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:662,&quot;width&quot;:890,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66249,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.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_!-faw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 424w, https://substackcdn.com/image/fetch/$s_!-faw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 848w, https://substackcdn.com/image/fetch/$s_!-faw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 1272w, https://substackcdn.com/image/fetch/$s_!-faw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F063f4386-fa9e-4507-abe7-b33644e3e5d5_890x662.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>LLMs are quite good at translation. Where they often fall down with invention, this kind of thing is their bread and butter. It even kept it compatible with the node server I started with.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7Q4g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7Q4g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 424w, https://substackcdn.com/image/fetch/$s_!7Q4g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 848w, https://substackcdn.com/image/fetch/$s_!7Q4g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 1272w, https://substackcdn.com/image/fetch/$s_!7Q4g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7Q4g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png" width="942" height="470" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:470,&quot;width&quot;:942,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:109130,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.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_!7Q4g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 424w, https://substackcdn.com/image/fetch/$s_!7Q4g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 848w, https://substackcdn.com/image/fetch/$s_!7Q4g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 1272w, https://substackcdn.com/image/fetch/$s_!7Q4g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47877ae0-f55a-4967-8cdd-9edbdda1580e_942x470.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Plus some goodies:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EAB2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EAB2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 424w, https://substackcdn.com/image/fetch/$s_!EAB2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 848w, https://substackcdn.com/image/fetch/$s_!EAB2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 1272w, https://substackcdn.com/image/fetch/$s_!EAB2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EAB2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png" width="946" height="598" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:598,&quot;width&quot;:946,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:135589,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.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_!EAB2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 424w, https://substackcdn.com/image/fetch/$s_!EAB2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 848w, https://substackcdn.com/image/fetch/$s_!EAB2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 1272w, https://substackcdn.com/image/fetch/$s_!EAB2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad686c31-965d-4776-a6ea-a6be74a3c582_946x598.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now, this doesn&#8217;t necessarily mean that non-mainstream technologies will be naturally surfaced over time, but, well&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!COw6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!COw6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 424w, https://substackcdn.com/image/fetch/$s_!COw6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 848w, https://substackcdn.com/image/fetch/$s_!COw6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 1272w, https://substackcdn.com/image/fetch/$s_!COw6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!COw6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif" width="480" height="192" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:192,&quot;width&quot;:480,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:867759,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!COw6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 424w, https://substackcdn.com/image/fetch/$s_!COw6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 848w, https://substackcdn.com/image/fetch/$s_!COw6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 1272w, https://substackcdn.com/image/fetch/$s_!COw6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a18203e-9f17-4ea2-bb42-e6ac6eca7469_480x192.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>If LLMs never get good enough to do things like troubleshoot esoteric technology and learn new things that weren&#8217;t in their training set, then they&#8217;ll fade into irrelevance anyway. So let&#8217;s extend this line of thinking out. If you think (like we probably all do) that your soup du jour is better than the other guy&#8217;s, then guess what? Either the LLMs will get &#8220;smart&#8221; enough to <strong>realize it too</strong>, or you&#8217;ll <strong>eat all the vibe coder&#8217;s lunch because they never figure it out.</strong></p><h2>Okay, so we&#8217;re all good then?</h2><p>Yes and no. I know there are a lot of people who will hate what I&#8217;m about to say. People I respect, and whose opinions I value despite how incorrect they are on this front. &#8220;AI&#8221; is going to significantly change what it looks like to build software. I&#8217;m not worried about how I&#8217;m going to stack up against the &#8220;<strong>Giving into the vibes, embrace exponentials, and forget that code even exists</strong>&#8221; folks, but I <strong>am</strong> aware that there are significant new tools &amp; variables at play here. Not factoring them in is how you become a dinosaur. Which, for what it's worth, is fully your prerogative. </p><p>With that in mind, if we want our tools to succeed in this space, we need to invest in it as well. Not exclusively, maybe even not significantly. But being relevant here is non-optional IMHO.</p><p>I&#8217;m the author of an application framework for Elixir called <a href="https://ash-hq.org">Ash Framework</a>. This article is not about Ash, but my work on it and the support that I provide for it have given me some potentially unique insights. Over the last few months I&#8217;ve observed:</p><ul><li><p>a new item on the rubric for tools: the quality of answers from Claude &amp; ChatGPT about it</p></li><li><p>a huge increase in fully off the wall and weird questions driven by LLM hallucinations</p></li><li><p>methodologies for working with LLM agents that are making me wish *more* of my users used them, not *less*</p></li></ul><div><hr></div><h2>The new rubric</h2><p>People are finding that the magic word smusher gives surprisingly good results for things like Typescript &amp; Rust. All of a sudden, they have a new thing to factor in when making their decisions. FOMO is a powerful thing, so I think this plays a bigger factor than we&#8217;d like. Folks are worrying even more than ever about the future-proofing of their knowledge in the context of a major industry shift. If I invest my time to learn something that &#8220;AI&#8221; can&#8217;t help me with, will I be left behind? It&#8217;s a very real and important question, and I think to succeed these days, you have to alleviate the concern in some way.</p><h2>The new headache</h2><p>Fairly often these days I get questions about code that no one would ever have had a reason to think should work. These cases are clearly coming from folks asking LLMs how to do something, or using an agentic assistant. The first knee-jerk response here is to tell people that we don&#8217;t answer questions about &#8220;AI&#8221; generated code. And in some cases, if it&#8217;s clear that the person asking the question did zero research on their own, they&#8217;ll get a response like that. But what if there was another way?</p><h1>Context is Key</h1><p>Ultimately you should not be relying on an LLM as a source of &#8220;knowledge&#8221;. This is true effectively <strong>always</strong>, even for popular tools, because LLMs won&#8217;t &#8220;know&#8221; about recent changes, but is magnified when asking questions about things that are more esoteric. </p><p>The key to succeeding with LLMs is to treat them as if they are only capable of doing things like summarization and pattern transformation. Assume that, before extracting an &#8220;answer&#8221; to your question, you must first do something that would *place* that answer into its context window, making its job the summarization and/or reformatting of the information into some desired result/effect. Here are some real things you can do to this effect.</p><h2>Research &amp; Investigate</h2><p>Here is a concrete example of using LLMs &#8220;badly&#8221;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DZ0_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DZ0_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 424w, https://substackcdn.com/image/fetch/$s_!DZ0_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 848w, https://substackcdn.com/image/fetch/$s_!DZ0_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 1272w, https://substackcdn.com/image/fetch/$s_!DZ0_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DZ0_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png" width="568" height="562.5384615384615" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1442,&quot;width&quot;:1456,&quot;resizeWidth&quot;:568,&quot;bytes&quot;:295003,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.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_!DZ0_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 424w, https://substackcdn.com/image/fetch/$s_!DZ0_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 848w, https://substackcdn.com/image/fetch/$s_!DZ0_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 1272w, https://substackcdn.com/image/fetch/$s_!DZ0_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2cd5ed29-49ee-4d89-9b3c-bb98d11b3f47_1488x1474.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Looks plausible enough right? But as you can guess, it&#8217;s just flat out wrong. Let&#8217;s try again, but better this time. I&#8217;ll cheat a bit because I know where the docs that it needs are.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wDQU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wDQU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 424w, https://substackcdn.com/image/fetch/$s_!wDQU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 848w, https://substackcdn.com/image/fetch/$s_!wDQU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!wDQU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wDQU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png" width="518" height="462.1442307692308" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1299,&quot;width&quot;:1456,&quot;resizeWidth&quot;:518,&quot;bytes&quot;:259003,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.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_!wDQU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 424w, https://substackcdn.com/image/fetch/$s_!wDQU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 848w, https://substackcdn.com/image/fetch/$s_!wDQU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 1272w, https://substackcdn.com/image/fetch/$s_!wDQU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca41d7-629d-446b-8552-458eb020e7b0_1614x1440.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Not only is this <strong>correct</strong>, but it continues on to provide advice that would likely be easy to miss if skimming the docs. See the <a href="https://claude.ai/share/80ff75b1-77ab-4d0c-8db4-b0ac0ad91e97">full answer here</a>. All of a sudden, I&#8217;m not in the world of &#8220;please stop using LLMs to answer your questions&#8221;, I&#8217;m in the world of &#8220;please stop using LLMs <strong>badly</strong> to answer your questions&#8221;. I knew where to find this documentation, but what if I didn&#8217;t?</p><p>Have a look at <a href="https://claude.ai/share/ec8b0563-d80b-4882-82e8-5504e3229a17">another way of asking this question</a>. First, I ask it to find the relevant docs. It does a great job. If you read the linked conversation, I then follow that up with the same question as before, and I get a correct answer without ever leaving Claude&#8217;s GUI.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0QaC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0QaC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 424w, https://substackcdn.com/image/fetch/$s_!0QaC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 848w, https://substackcdn.com/image/fetch/$s_!0QaC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 1272w, https://substackcdn.com/image/fetch/$s_!0QaC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0QaC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png" width="626" height="639.0235783633842" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1472,&quot;width&quot;:1442,&quot;resizeWidth&quot;:626,&quot;bytes&quot;:397906,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.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_!0QaC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 424w, https://substackcdn.com/image/fetch/$s_!0QaC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 848w, https://substackcdn.com/image/fetch/$s_!0QaC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 1272w, https://substackcdn.com/image/fetch/$s_!0QaC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3422f22c-60ae-453d-856f-fbc6c05aff51_1442x1472.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Bonus - Use <a href="http://tidewave.ai">Tidewave</a></h2><p>Tidewave is a server that speaks MCP (Model Context Protocol) that you can serve directly from your application. Think of it as giving your LLM a direct hotline to your running code - not just static documentation, but your actual living application.</p><p>Here's what this looks like in practice. Instead of asking Claude "How do I create a user in this app?" and getting a generic answer that might be outdated, Tidewave lets the LLM use tools like:</p><ul><li><p><code>project_eval</code> - runs code snippets directly in your application context</p></li><li><p><code>run_sql_query</code> - executes database queries using your app's actual schema and tooling</p></li><li><p><code>search_hex_docs</code> - searches the documentation of your specific package versions</p></li></ul><p>This means your agent might do things like search the hex docs of your dependencies to see how Ash works, use the `project_eval` tool to poke around in your running app, try creating a user using your app to see if it works, and then run a SQL query after the fact to make sure the user exists in the database. Wildly powerful stuff.</p><h2>Make me an X like Y</h2><p>This one is easy, and you can try it on your own apps today. Often when you end up building new features, they bear resemblance to one or more of the other things in your application. LLMs are very good at synthesis, summary, and categorization. So put them to work at it! A really excellent prompt to kick off an agent&#8217;s task often looks like this:</p><pre><code>I'd like to make a feature to track user activity. Let's start with "last_login_at" and "last_seen_at". To start, we'll need a new plug in our router, kind of like @/path/to/similar/plug.ex, except instead of X it does Y. For the fields, take a look at `last_updated` for an example of the kind of field we want, except this one should be accepted as input when updating a user.</code></pre><h2>Crowdsource your context</h2><p>I'm trying to push a new pattern for Elixir packages that I think could be game-changing. The concept is simple: any library can include a <code>usage-rules.md</code> file - essentially very terse documentation designed specifically for LLM context windows, explaining what to and what not to do when using the library.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wtZl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wtZl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 424w, https://substackcdn.com/image/fetch/$s_!wtZl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 848w, https://substackcdn.com/image/fetch/$s_!wtZl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 1272w, https://substackcdn.com/image/fetch/$s_!wtZl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wtZl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png" width="598" height="257.51785714285717" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:627,&quot;width&quot;:1456,&quot;resizeWidth&quot;:598,&quot;bytes&quot;:64317,&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.zachdaniel.dev/i/164927613?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.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_!wtZl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 424w, https://substackcdn.com/image/fetch/$s_!wtZl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 848w, https://substackcdn.com/image/fetch/$s_!wtZl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 1272w, https://substackcdn.com/image/fetch/$s_!wtZl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ab20e2c-906b-483c-9c9f-cd7452e8ced4_2080x896.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We've done this for the main Ash packages, and the transformation is remarkable. We went from LLM agents being practically useless for Ash development to being able to generate idiomatic, production-ready code. The dichotomy of "meet my standards" versus "let the LLM do it" simply disappeared.</p><p>This isn't just about Ash or even Elixir. This is a template for how any technology community can turn LLMs from a threat into their most effective growth tool.</p><h2>Evals: Training the Trainers</h2><p>We can go even further. Instead of just helping LLMs use Elixir better, we can help train them to be better at Elixir in the first place. This is something we discussed at the contributors summit, so it is the product of many minds, not just mine.</p><p>The Elixir community could build evaluation datasets that test real-world scenarios: GenServer supervision trees, OTP fault tolerance patterns, Phoenix LiveView reactivity, writing Ecto queries, building applications with Ash. When companies like Anthropic and OpenAI train their models, they need diverse, high-quality benchmarks - and right now, they're mostly testing on Python and JavaScript.</p><p>If we get these evaluations to a degree of quality and scale, we get a bunch of benefits. We can determine which models are the best at writing Elixir. If done well enough, companies like OpenAI and Anthropic may even opt to use it to train their private models (something we should encourage in this scenario). You can find collections of benchmarks in various places, like: <a href="https://huggingface.co">Hugging Face</a> and <a href="https://github.com/leobeeson/llm_benchmarks">GitHub</a>. I see plenty of python stuff there, but not no Elixir &#129300;.</p><p>Here's the kicker: Elixir's runtime makes it perfect for performance-based evals. We can build harnesses that don't just check if code compiles, but whether it actually handles concurrent load properly, recovers from crashes gracefully, or manages memory efficiently.</p><p>As models get better at Elixir through these evaluations, they become better advocates for it. We would be going beyond just making LLMs write better Elixir - we'd be making them recommend Elixir when it's the right choice.</p><div><hr></div><p>If I can make LLMs a force to be reckoned with not only for Elixir but for the niche-within-a-niche that is Ash Framework, I think it's safe to say that LLMs are not, in-and-of-themselves, an existential threat to Elixir.</p><p>In fact, I think we're looking at this backwards. The real opportunity isn't surviving the LLM revolution - it's using it as a force multiplier. Better technologies have lost adoption battles because they had steeper learning curves or less accessible documentation, but maybe LLMs can flatten that learning curve if we do the work to make our tools competitive in this space.</p><p>The question isn't whether LLMs will change how we build software. They already have. The question is whether we'll shape that change or let it shape us.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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! 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[Now Available: Ash Framework Book!]]></title><description><![CDATA[Get your copy of the beta today! Plus: New Homepage & Installer!]]></description><link>https://www.zachdaniel.dev/p/now-available-ash-framework-book</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/now-available-ash-framework-book</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Sun, 19 Jan 2025 16:42:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!pNXQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey folks! Many of you may already be aware, but I&#8217;m pleased to share with you all that the Ash Framework book is now available in beta! This book is, frankly, the best way to learn Ash. By <em>far</em>. If you&#8217;re using Ash professionally, I cannot recommend it enough. We still have three chapters coming and they are the <em>most exciting chapters</em>. Up next is the testing chapter, packed with practical testing patterns and insider tips!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://pragprog.com/titles/ldash/ash-framework/" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pNXQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 424w, https://substackcdn.com/image/fetch/$s_!pNXQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 848w, https://substackcdn.com/image/fetch/$s_!pNXQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!pNXQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pNXQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg" width="322" height="386.3557692307692" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1747,&quot;width&quot;:1456,&quot;resizeWidth&quot;:322,&quot;bytes&quot;:241736,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:&quot;https://pragprog.com/titles/ldash/ash-framework/&quot;,&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_!pNXQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 424w, https://substackcdn.com/image/fetch/$s_!pNXQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 848w, https://substackcdn.com/image/fetch/$s_!pNXQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!pNXQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F290a85ec-920f-4c0d-b5ba-ea04483e550b_2250x2700.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Get your copy on <a href="https://pragprog.com/titles/ldash/ash-framework/">pragprog.com</a></figcaption></figure></div><p>I&#8217;m really proud of this book. Rebecca Le is an amazing writer and working with her has been extremely rewarding and fun! </p><p>In other big news, I&#8217;d like to congratulate her on joining the core team! She has earned it time and time again, even without her amazing work on the book. The book, which happens to be one of the most significant contributions made to the Ash ecosystem ever.</p><h2>New Weekly Newsletter</h2><p>We&#8217;ve launched the Ash Weekly Newsletter! Its the best place to stay up to date with what is happening in Ash news &#128526;</p><div class="embedded-publication-wrap" data-attrs="{&quot;id&quot;:3792836,&quot;name&quot;:&quot;Ash Weekly&quot;,&quot;logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F364f7835-1677-422c-8c92-3abcfbcf647f_500x500.png&quot;,&quot;base_url&quot;:&quot;https://ashweekly.substack.com&quot;,&quot;hero_text&quot;:&quot;A weekly the goings on of the Ash Framework ecosystem.&quot;,&quot;author_name&quot;:&quot;Zach Daniel&quot;,&quot;show_subscribe&quot;:true,&quot;logo_bg_color&quot;:&quot;#171717&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="EmbeddedPublicationToDOMWithSubscribe"><div class="embedded-publication show-subscribe"><a class="embedded-publication-link-part" native="true" href="https://ashweekly.substack.com?utm_source=substack&amp;utm_campaign=publication_embed&amp;utm_medium=web"><img class="embedded-publication-logo" src="https://substackcdn.com/image/fetch/$s_!aoER!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F364f7835-1677-422c-8c92-3abcfbcf647f_500x500.png" width="56" height="56" style="background-color: rgb(23, 23, 23);"><span class="embedded-publication-name">Ash Weekly</span><div class="embedded-publication-hero-text">A weekly the goings on of the Ash Framework ecosystem.</div><div class="embedded-publication-author-name">By Zach Daniel</div></a><form class="embedded-publication-subscribe" method="GET" action="https://ashweekly.substack.com/subscribe?"><input type="hidden" name="source" value="publication-embed"><input type="hidden" name="autoSubmit" value="true"><input type="email" class="email-input" name="email" placeholder="Type your email..."><input type="submit" class="button primary" value="Subscribe"></form></div></div><h2>New Website</h2><p>The <a href="https://ash-hq.org">AshHQ website</a> has been completely revamped, both for a modernized look but also to make room for&#8230;</p><h2>New Installer</h2><p>We&#8217;ve got an awesome new installer experience available on the new website! It&#8217;s really flashy and fun to use, and something that we will continue to evolve over time. It acts both as an overview of all kinds of capabilities in Ash, but also to highlight the modularity of the ecosystem, and the way that any thing can be installed <em>later.</em> No need to decide up front what you want. (Still have some planned changes to make that clear in the installer)</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;d8246944-a503-439a-bd00-de4ff402adde&quot;,&quot;duration&quot;:null}"></div><h2>Thank you</h2><p>To those at Alembic and our technical reviewers <em>thank you! </em>To those who have already given us such great feedback on the book <em>thank you!</em> To those who encouraged us and helped us along the way, my wonderful wife and family, <em>thank you</em>.</p><p>I hope that you all enjoy the book. If you pick up a copy I&#8217;d love to hear your thoughts.</p>]]></content:encoded></item><item><title><![CDATA[Serialization is the Secret]]></title><description><![CDATA[If a value mutates in the forest with no one to see it, does it really mutate?]]></description><link>https://www.zachdaniel.dev/p/serialization-is-the-secret</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/serialization-is-the-secret</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Fri, 27 Sep 2024 21:30:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kN7J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One of the major elements that sets Elixir apart from most other programming languages is <em>immutability. </em>But what does that <em>actually</em> mean? What does it do for us?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kN7J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kN7J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!kN7J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!kN7J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!kN7J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kN7J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp" width="360" height="360" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:360,&quot;bytes&quot;:444248,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kN7J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!kN7J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!kN7J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!kN7J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0497788-9426-45ac-abe6-4ffb3a6ee35f_1024x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The word immutable is defined by Merriam-Webster as &#8220;not capable of or susceptible to change&#8221;. If nothing ever <em>observes</em> a change, it may as well have not happened anyway, so we will be discussing mutation as two discrete concepts: mutation, and the <em>observation</em> of mutation.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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 Zach Daniel! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Here is a simple example of a mutable program in Javascript.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6EWF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6EWF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 424w, https://substackcdn.com/image/fetch/$s_!6EWF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 848w, https://substackcdn.com/image/fetch/$s_!6EWF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 1272w, https://substackcdn.com/image/fetch/$s_!6EWF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6EWF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png" width="346" height="160" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:160,&quot;width&quot;:346,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10308,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6EWF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 424w, https://substackcdn.com/image/fetch/$s_!6EWF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 848w, https://substackcdn.com/image/fetch/$s_!6EWF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 1272w, https://substackcdn.com/image/fetch/$s_!6EWF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff221a286-b09d-4853-8a79-06ac9cca68a3_346x160.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Here is a simple example of an immutable program in Elixir.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bUuj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bUuj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 424w, https://substackcdn.com/image/fetch/$s_!bUuj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 848w, https://substackcdn.com/image/fetch/$s_!bUuj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 1272w, https://substackcdn.com/image/fetch/$s_!bUuj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bUuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png" width="344" height="147.2" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:184,&quot;width&quot;:430,&quot;resizeWidth&quot;:344,&quot;bytes&quot;:9405,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bUuj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 424w, https://substackcdn.com/image/fetch/$s_!bUuj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 848w, https://substackcdn.com/image/fetch/$s_!bUuj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 1272w, https://substackcdn.com/image/fetch/$s_!bUuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2607fa7c-5a27-4519-9368-77e0f77a04ce_430x184.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>They look very similar. And in fact, they both have consistent behavior if the next line of the program was to print out the value of counter. We are guaranteed in both cases to see the value <code>1 </code>printed. It would <em>appear</em> that the <em>observation</em> of variables behaves the same.</p><h3>Rebinding vs Mutation</h3><p>Before I explain the benefits of immutability, it&#8217;s important to disambiguate something that folks often initially <em>believe</em> is mutation.</p><p>In the Javascript example, our <em>reference</em> to the counter is <em>mutated<strong>. </strong></em>However, in the Elixir example, what we&#8217;ve done is <em>rebound</em> the variable. No pointers or values have changed. In Javascript, primitive values are immutable, but a variable&#8217;s reference is not. In later examples we&#8217;ll see how Javascript allows mutating other values i.e objects, called reference values.</p><p>The first is an actual mutation of memory. The second is an allocation of new memory. The old memory is unaffected. One could argue that this is a form of mutation. This mutation, however, is <em>syntactic.</em></p><p>This is a convenience that the language provides. When you <em>rebind</em> a variable, it is equivalent to creating a new variable, and altering references to that variable in the same scope to use that new name instead. Let&#8217;s look at what this means in practice. </p><p>In Javascript, we mutate the actual underlying memory. What this looks like in practice:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mhmU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mhmU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 424w, https://substackcdn.com/image/fetch/$s_!mhmU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 848w, https://substackcdn.com/image/fetch/$s_!mhmU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 1272w, https://substackcdn.com/image/fetch/$s_!mhmU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mhmU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png" width="386" height="282.8448275862069" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:340,&quot;width&quot;:464,&quot;resizeWidth&quot;:386,&quot;bytes&quot;:21240,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mhmU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 424w, https://substackcdn.com/image/fetch/$s_!mhmU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 848w, https://substackcdn.com/image/fetch/$s_!mhmU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 1272w, https://substackcdn.com/image/fetch/$s_!mhmU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F357daaa5-a1fb-4ee6-9ff7-b8c53b89ca38_464x340.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Notice how the value for <code>counter </code>is now <code>1</code>. In Elixir, however, this behaves differently.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NU03!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NU03!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 424w, https://substackcdn.com/image/fetch/$s_!NU03!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 848w, https://substackcdn.com/image/fetch/$s_!NU03!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 1272w, https://substackcdn.com/image/fetch/$s_!NU03!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NU03!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png" width="386" height="282.8448275862069" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:340,&quot;width&quot;:464,&quot;resizeWidth&quot;:386,&quot;bytes&quot;:21725,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!NU03!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 424w, https://substackcdn.com/image/fetch/$s_!NU03!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 848w, https://substackcdn.com/image/fetch/$s_!NU03!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 1272w, https://substackcdn.com/image/fetch/$s_!NU03!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa19b06cb-a7ba-4875-be09-91ddcd358109_464x340.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>How can this be? We&#8217;ve clearly reassigned <code>counter</code>. The reason for this is that <em>rebinding</em> is equivalent to creating a new variable. Just like in Javascript, a variable is not available outside of the scope it was defined in. The Elixir code is <em>effectively </em>rewritten to this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hCvo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hCvo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 424w, https://substackcdn.com/image/fetch/$s_!hCvo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 848w, https://substackcdn.com/image/fetch/$s_!hCvo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 1272w, https://substackcdn.com/image/fetch/$s_!hCvo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hCvo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png" width="378" height="267.75" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:340,&quot;width&quot;:480,&quot;resizeWidth&quot;:378,&quot;bytes&quot;:21960,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hCvo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 424w, https://substackcdn.com/image/fetch/$s_!hCvo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 848w, https://substackcdn.com/image/fetch/$s_!hCvo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 1272w, https://substackcdn.com/image/fetch/$s_!hCvo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a248a51-e7f9-4400-a2c8-224c0e7ea6c3_480x340.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In this way, no reference to a given variable can ever truly be mutated in Elixir. You only ever create new bindings with new values. There is just a language level construct that allows you to reuse the same variable name.</p><h3>Cool, so why immutability?</h3><p>Now that you understand that rebinding isn&#8217;t mutation, you can see the fact that the value of a given variable will <em>never</em> change. This lends itself to well to understandable code. For example, in Javascript, objects are mutable, and are passed to functions by reference. Which means that calling functions can do &#8220;surprising stuff&#8221;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kClO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kClO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 424w, https://substackcdn.com/image/fetch/$s_!kClO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 848w, https://substackcdn.com/image/fetch/$s_!kClO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 1272w, https://substackcdn.com/image/fetch/$s_!kClO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kClO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png" width="420" height="314.6488294314381" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:448,&quot;width&quot;:598,&quot;resizeWidth&quot;:420,&quot;bytes&quot;:48283,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kClO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 424w, https://substackcdn.com/image/fetch/$s_!kClO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 848w, https://substackcdn.com/image/fetch/$s_!kClO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 1272w, https://substackcdn.com/image/fetch/$s_!kClO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e0d49d4-1c1e-4bd8-bca5-aaebe67b82ef_598x448.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>After executing this code, <code>profile</code> has <em>mutated</em>. Before calling <code>newScore</code>, <code>profile.score</code> was <code>3</code>. Afterwards, it is <code>7. </code>This would be a pretty beginner mistake to make, but it is still something that you have to contend with. You will always have to consider using things like <code>Object.freeze</code> or <code>Object.seal</code>, or just trusting that your other code makes no mutations to the parameters that you pass in.</p><p>In Elixir, it is <em>just not possible</em> for that to happen. If I call a function, it can do all kinds of side effects, but it will <em>never</em> be able to affect the values of the variables that are currently in scope for me. </p><p>This is where <em>observation</em> of mutation comes into play. In the Javascript example, mutation can be observed effectively at any time. If I started an async function, for example, and passed in a mutable variable, it could change <em>at any time</em>.</p><h3>Time: the most frustrating part of programming</h3><p>And I don&#8217;t mean dealing with time zones. Although maybe <em>that</em> actually is the most frustrating part of programming.</p><p>What I mean is handling the passage of time. Let&#8217;s go back to our Javascript example, and introduce some concurrency. When concurrency comes into play, we can no longer think in terms of a discrete, causal series of events. Instead, we have to think of &#8220;state over time&#8221;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_35T!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_35T!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 424w, https://substackcdn.com/image/fetch/$s_!_35T!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 848w, https://substackcdn.com/image/fetch/$s_!_35T!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 1272w, https://substackcdn.com/image/fetch/$s_!_35T!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_35T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png" width="496" height="323.6807511737089" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:556,&quot;width&quot;:852,&quot;resizeWidth&quot;:496,&quot;bytes&quot;:74836,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_35T!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 424w, https://substackcdn.com/image/fetch/$s_!_35T!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 848w, https://substackcdn.com/image/fetch/$s_!_35T!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 1272w, https://substackcdn.com/image/fetch/$s_!_35T!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a5a6f6d-decf-4acd-828d-266aed25d805_852x556.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The value of <code>profile.score</code> at the end of this program is <em>entirely dependent</em> on how long it takes to <code>doSomethingElse(). </code>That means that sequential runs of this program can produce different results. There are absolutely steps to mitigate this. For instance, you can <code>await</code> newScore. You can make <code>doSomethingElse()</code> an <code>async</code> function, and await them both using <code>Promise.all()</code>.</p><p>But imagine that you had passed `profile` into both of those now-async functions? And each one modified it at a different time? Handling race conditions like this can be very difficult, and oftentimes immutable data structures are <em>the </em>solution. You can use things like locks and mutexes, but that is just as easy to get wrong as any other thing.</p><p>So, to summarize, mutation can <em>occur</em> at any time and can also be <em>observed</em> at any time in Javascript.</p><h3>Elixir is not, by all definitions, completely immutable</h3><p>In Elixir, everything runs in a process. It is a garbage collected language. Each process has its own stack, and its own heap. This garbage collection means that the memory location of a variable can technically <a href="https://www.erlang.org/doc/apps/erts/garbagecollection.html#the-collector">change</a> at any time. So from a pedantic standpoint, you could have two variables whose memory location swaps at some point while running your program. This is transparent to the programmer (which is good). </p><p>With this in mind, an argument could be made that anything stored in a process&#8217;s heap is mutable state. For example, let&#8217;s take a simple, GenServer-backed counter in Elixir. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dFtY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dFtY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 424w, https://substackcdn.com/image/fetch/$s_!dFtY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 848w, https://substackcdn.com/image/fetch/$s_!dFtY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 1272w, https://substackcdn.com/image/fetch/$s_!dFtY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dFtY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png" width="494" height="370.22121896162525" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:664,&quot;width&quot;:886,&quot;resizeWidth&quot;:494,&quot;bytes&quot;:85220,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dFtY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 424w, https://substackcdn.com/image/fetch/$s_!dFtY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 848w, https://substackcdn.com/image/fetch/$s_!dFtY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 1272w, https://substackcdn.com/image/fetch/$s_!dFtY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0bf4247-2955-4117-a73e-8a10f19a0c6e_886x664.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When I increment this counter, new memory is allocated for the new number to live in. When I access this counter, I&#8217;m reading from that memory location. At some point, a garbage collection comes through, cleaning up the references to the old variables, and potentially moving the location of the new variable in memory.</p><p>So this process, while indirect, actually has all of the hallmarks of <em>mutation</em>! The same variable changing its location in memory in a way that is completely out of the developer&#8217;s control. Other variables being removed from memory or moved around at any time. SpoOoOoky!</p><p>So Elixir is mutable then? By some definitions, sure. In Elixir, <em>values</em> are immutable, but ultimately there is state, somewhere in our system. And it even changes over time! So what gives? </p><p>There are two secret sauces in the Elixir restaurant. They are:</p><ul><li><p>Function calling as the only way to observe mutating state</p></li></ul><ul><li><p>Serialized access to mutating state</p></li></ul><h3>Function calling as the only way to observe mutating state</h3><p>Something we have available to us in Elixir is the &#8220;process dictionary&#8221;. By many definitions, the process dictionary is mutable state. I would argue that, from the perspective of our program, it is not more or less mutable than any other thing. The reason for this, is that in Elixir, all mutating state requires calling a function to observe it.</p><p>Want to know the current time? You must call <code>DateTime.now(). </code>You can change the process dictionary with <code>Process.put</code>. You can even call a function that makes this change. Lets look at an example based on the Javascript &#8220;mutating profile&#8221; example from before:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GBTT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GBTT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 424w, https://substackcdn.com/image/fetch/$s_!GBTT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 848w, https://substackcdn.com/image/fetch/$s_!GBTT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 1272w, https://substackcdn.com/image/fetch/$s_!GBTT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GBTT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png" width="456" height="338.048" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:556,&quot;width&quot;:750,&quot;resizeWidth&quot;:456,&quot;bytes&quot;:73977,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GBTT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 424w, https://substackcdn.com/image/fetch/$s_!GBTT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 848w, https://substackcdn.com/image/fetch/$s_!GBTT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 1272w, https://substackcdn.com/image/fetch/$s_!GBTT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe76279ea-529b-4484-ae4b-20c3b84e83f1_750x556.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here we are &#8220;mutating&#8221; the process dictionary state. It was one thing, and now it is something else. However, we cannot <em>observe</em> this mutation without calling <code>Process.get. </code>The <code>profile </code>variable will always, unambiguously, equal <code>%{score: 3}</code>. The only way that could change is by reassigning the variable, and calling a function. For example:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZouV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZouV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 424w, https://substackcdn.com/image/fetch/$s_!ZouV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 848w, https://substackcdn.com/image/fetch/$s_!ZouV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 1272w, https://substackcdn.com/image/fetch/$s_!ZouV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZouV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png" width="418" height="394.1501501501501" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:628,&quot;width&quot;:666,&quot;resizeWidth&quot;:418,&quot;bytes&quot;:81236,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZouV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 424w, https://substackcdn.com/image/fetch/$s_!ZouV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 848w, https://substackcdn.com/image/fetch/$s_!ZouV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 1272w, https://substackcdn.com/image/fetch/$s_!ZouV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F794bfb52-1460-4f10-9ef4-335db0233f52_666x628.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Our variable values are always safe in Elixir &#129395;</p><h3>Serialized access to mutating state</h3><p>This is the most important part of the whole equation. We&#8217;ve shown that we can accomplish mutating state in Elixir, albeit in a different way than you might have seen elsewhere. But what about the race condition example from before? We can&#8217;t really write an equivalent example to that in Elixir. Our concurrency primitive is to start another process, which has its own isolated process dictionary. There is no way to modify another process&#8217;s state.</p><p>So we&#8217;ll base this on our counter example, which is how you&#8217;d actually do This Kind Of Thing&#8482; in Elixir. Each process handles messages serially, one-at-a-time. This means that, from the perspective of the counter, there is no such thing as a race condition! And callers, in order to interact with the counter, must call functions to send it a message, or to observe its changing state. Nothing the counter does can modify the state of the callers.</p><p><strong>By forcing the mutation of state to be serialized through a process&#8217;s mailbox, and limiting the observation of mutating state to calling functions, our programs are more understandable, and less surprising.</strong></p><h3>What&#8217;s next?</h3><p>There is a lot more to say on this topic, and I fully intend to do so! Understandability and predictability are not the only benefits of the concepts described above. Many of the benefits only even come into the picture when it&#8217;s time to scale, or to model graceful failure of our application components, and its those properties that I&#8217;ll be writing about next.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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 Zach Daniel! 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[Sending Emails with Ash Framework]]></title><description><![CDATA[A.K.A - Burying the lede on using Oban]]></description><link>https://www.zachdaniel.dev/p/sending-emails-with-ash</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/sending-emails-with-ash</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Fri, 20 Sep 2024 14:50:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!SUCz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Most applications need to send emails, and there are a few different ways to set this up with <a href="http://ash-hq.org">Ash</a>. Let's dive in!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SUCz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SUCz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!SUCz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!SUCz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!SUCz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SUCz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp" width="326" height="326" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:326,&quot;bytes&quot;:395088,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SUCz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!SUCz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!SUCz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!SUCz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f7a219-2073-4424-bafd-dd78d0ddf26d_1024x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We won&#8217;t be going into the details of the what service or tool you use to <em>actually </em>send emails. The most common setup is using <a href="https://hexdocs.pm/swoosh/Swoosh.html">Swoosh</a> with something like <a href="https://postmarkapp.com">Postmark</a> or <a href="https://sendgrid.com/en-us">Sendgrid</a>. Phoenix sets you up with this out of the box, or you can look at the Swoosh docs to set it up yourself.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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 Zach Daniel! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Here, we will be focused on how to architect your resources to get the guarantees you need from sending emails. We&#8217;ll start with the simple/least-powerful method and work our way up.</p><p>We&#8217;ll base this example on a real use case from <a href="https://elixirforum.com/t/sending-email-as-part-of-an-action/66203/3">ElixirForum</a> (my answer to which the content of this post has been adapted from). We want to send users an email when someone comments on their post. Simple, right?</p><h3>Before we dive in</h3><p>In all of these examples I&#8217;m using &#8220;inline changes&#8221;. This is not actually best practice, you should prefer to extract your changes to modules that use <a href="https://hexdocs.pm/ash/changes.html">Ash.Resource.Change</a><code>, but inline functions are much simpler for demonstration.</code></p><p>It&#8217;s very important to keep in mind that <a href="https://en.wikipedia.org/wiki/CAP_theorem">CAP theorem</a> limits us here. Specifically, your email sending service and your app together create a distributed system. There is <em>no such thing</em> as &#8220;exactly once&#8221;, where something in your application can be <em>100%</em> guaranteed to only send one email. I&#8217;ll probably say something along these lines in a lot of my posts&#8230;but it bears repeating.</p><p>This means you <em>are always</em> choosing between one of two alternatives: <strong>at most once delivery</strong>, and <strong>at least once delivery</strong>. Especially when you get retries involved, <strong>at most once</strong> technically includes &#8220;maybe never&#8221;, and <strong>at least once</strong> technically includes &#8220;maybe a million times&#8221;. A lot of tooling around background jobs involve tools to help curtail this problem to a reasonable set of constraints. </p><p>I will detail how these guarantees apply to each of our strategies below.</p><h3>After Action Hooks (at least once)</h3><p>After action hooks happen <em>in the transaction with the action</em>. What this means is that you could send an email, and then an error could occur, and you&#8217;ll have sent an email for a comment that was not actually created. In <em>some</em> cases you may actually want that, but in this case it makes this strategy less-than-ideal. </p><p>Another ramification of this strategy is that <em>errors sending emails</em> could potentially prevent a comment&#8217;s creation. This is naturally not something we want interrupting our user&#8217;s experience.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tdfz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tdfz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 424w, https://substackcdn.com/image/fetch/$s_!tdfz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 848w, https://substackcdn.com/image/fetch/$s_!tdfz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 1272w, https://substackcdn.com/image/fetch/$s_!tdfz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tdfz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png" width="586" height="425.58659217877096" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:520,&quot;width&quot;:716,&quot;resizeWidth&quot;:586,&quot;bytes&quot;:65694,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tdfz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 424w, https://substackcdn.com/image/fetch/$s_!tdfz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 848w, https://substackcdn.com/image/fetch/$s_!tdfz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 1272w, https://substackcdn.com/image/fetch/$s_!tdfz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0740f22c-da07-41c4-8e22-ab5ab616e153_716x520.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The above implementation was simple, and could be good if you wanted to send an email perhaps notifying some owner of a resource every time someone <em>even attempts</em> to perform an action. Not in this use case though.</p><h3>After Transaction Hooks (at most once)</h3><p>After transaction hooks happen(you guessed it) <em>after</em> the transaction has been committed. It is also the only hook in Ash that is invoked both on success <em>and</em> failure. In the example below, we get better behavior in the case of errors than in the above example. </p><p>If something goes wrong, the user may not get an email. Additionally, if something goes wrong sending an email, the user might experience an errored request, but their comment will still have successfully been created. <em>Better</em> UX, but not perfect.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VzEv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VzEv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 424w, https://substackcdn.com/image/fetch/$s_!VzEv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 848w, https://substackcdn.com/image/fetch/$s_!VzEv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 1272w, https://substackcdn.com/image/fetch/$s_!VzEv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VzEv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png" width="768" height="592" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:592,&quot;width&quot;:768,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80568,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VzEv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 424w, https://substackcdn.com/image/fetch/$s_!VzEv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 848w, https://substackcdn.com/image/fetch/$s_!VzEv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 1272w, https://substackcdn.com/image/fetch/$s_!VzEv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0153c86-85c1-4614-afd6-a7e2e7ee7cf6_768x592.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The above implementation was simple, just like the first one, and has some better properties. </p><p>It still has some undesirable properties. If something goes wrong sending an email, the caller could get an error, even though the transaction was submitted. You could handle this with defensive coding.</p><p>Even worse, however, is that this doesn&#8217;t &#8220;compose&#8221; with other actions calling it. For example, say you had something like an <code>add_many_comments</code> action, and that action called this action multiple times in a transaction. When calling that action, you&#8217;d get a warning printed that Ash is running an <code>after_transaction</code> hook in a transaction. This happens because the transaction was already started when this action was called.</p><h3>Notifiers (at most once)</h3><p>Ash has a system designed to solve exactly the problem described above. We call these &#8220;notifiers&#8221;. Specifically, their job is to do some post-transaction work, to notify other parts of your system (or users) of what has transpired. The most common notifier is <a href="https://hexdocs.pm/ash/dsl-ash-notifier-pubsub.html">Ash.Notifier.PubSub</a>. However, writing your own is as simple as defining a <code>notify/3</code> function!</p><p>Notifications are all automatically accumulated by Ash, and send after the final transaction has been committed. This is very useful for live systems! It prevents pub sub messages going out for data that has not yet been created or modified, and it gives you action side-effects that are <strong>at least once.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jx5E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jx5E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 424w, https://substackcdn.com/image/fetch/$s_!jx5E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 848w, https://substackcdn.com/image/fetch/$s_!jx5E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 1272w, https://substackcdn.com/image/fetch/$s_!jx5E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jx5E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png" width="582" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:582,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80261,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jx5E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 424w, https://substackcdn.com/image/fetch/$s_!jx5E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 848w, https://substackcdn.com/image/fetch/$s_!jx5E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 1272w, https://substackcdn.com/image/fetch/$s_!jx5E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbd56add-8d8a-40c0-8e91-43091dc8000d_582x700.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now, our action is composable! Creating many comments in a single transactional action will send notifications after that transaction has closed. However, you still have to program defensively around errors, as errors in notifiers will still incur errors happening in your app. </p><p>For this reason, notifiers typically should just dispatch a message to something else running in your app to handle the work they are meant to do.</p><h3>All of the above approaches have some flaws</h3><p>The above approaches are relatively simple, but what about retries? The things that happen in an action are awaited by the user. Do you really want email sending code mixed in with your app code? Do you want users <em>waiting</em> on sending an email for your app to respond? Almost certainly not. </p><p>There is a better way, and that is with our wonderful friends <a href="https://getoban.pro">Oban</a>! Oban&#8217;s free features are more than enough to power this functionality, but their pro plan offers some awesome features. I highly advise checking it out, as it&#8217;s a staple tool in the Elixir ecosystem (this is not a sponsored statement).</p><h3>With Oban (at least once/at most once)</h3><p>Oban provides all the guarantees we want, and also allows our action to transactionally insert the &#8220;request&#8221; for an email to be sent. Anything going wrong with the email will not affect our response to the user, and if an error happens after inserting the job, the transaction is rolled back and no email will be sent.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FbYC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FbYC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 424w, https://substackcdn.com/image/fetch/$s_!FbYC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 848w, https://substackcdn.com/image/fetch/$s_!FbYC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 1272w, https://substackcdn.com/image/fetch/$s_!FbYC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FbYC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png" width="650" height="412" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/17be4e18-b123-442b-a188-53b32f9183d3_650x412.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:412,&quot;width&quot;:650,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:48191,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FbYC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 424w, https://substackcdn.com/image/fetch/$s_!FbYC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 848w, https://substackcdn.com/image/fetch/$s_!FbYC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 1272w, https://substackcdn.com/image/fetch/$s_!FbYC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17be4e18-b123-442b-a188-53b32f9183d3_650x412.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>With the above strategy, you&#8217;d implement and configure an <a href="https://hexdocs.pm/oban/Oban.Worker.html">Oban Worker</a> by hand, and in that Oban worker you&#8217;d send your email. The way that you opt into <strong>at most once</strong> or <strong>at least once</strong> in this case is entirely dependent on your Oban configuration.</p><h4>Using AshOban (at least once/at most once)</h4><p>With this strategy, we leverage data to our advantage. Instead of making an Oban queue the authoritative representation of &#8220;emails that will be sent&#8221;, we use an <code>Ash.Resource</code>, configured with an `ash_oban` trigger.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I8wm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I8wm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 424w, https://substackcdn.com/image/fetch/$s_!I8wm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 848w, https://substackcdn.com/image/fetch/$s_!I8wm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 1272w, https://substackcdn.com/image/fetch/$s_!I8wm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I8wm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png" width="768" height="1348" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1348,&quot;width&quot;:768,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:163808,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I8wm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 424w, https://substackcdn.com/image/fetch/$s_!I8wm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 848w, https://substackcdn.com/image/fetch/$s_!I8wm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 1272w, https://substackcdn.com/image/fetch/$s_!I8wm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e215a92-fb88-4692-9de3-91cae11b439a_768x1348.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>With this setup, in my :create action I would create a <code>NewCommentEmail</code> instead of directly inserting the Oban job. The above case has &#8220;at most once&#8221; guarantees because it changes the state to sent, and then sends the email in an <code>after_transaction</code> hook. This means that the scheduler won&#8217;t ever reschedule this particular email, even if something goes wrong while sending.</p><p>If I want <strong>at least once</strong> guarantees, I can change that to a <code>before_transaction </code>hook. Easy-peasy.</p><p>There are other awesome benefits to this data-driven strategy of creating a <code>NewCommentEmail</code> row in a database table. Want to know how many emails have been sent ever, and how many are waiting to be sent?</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AB4Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AB4Y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 424w, https://substackcdn.com/image/fetch/$s_!AB4Y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 848w, https://substackcdn.com/image/fetch/$s_!AB4Y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 1272w, https://substackcdn.com/image/fetch/$s_!AB4Y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AB4Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png" width="728" height="197.87423935091277" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:268,&quot;width&quot;:986,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:48862,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AB4Y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 424w, https://substackcdn.com/image/fetch/$s_!AB4Y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 848w, https://substackcdn.com/image/fetch/$s_!AB4Y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 1272w, https://substackcdn.com/image/fetch/$s_!AB4Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94652988-7b48-401c-b15d-96844b8cdbeb_986x268.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Want to cancel a specific email from being sent? You can add a <code>:canceled </code>state and an action to set that new state. Even if the worker is in the queue to run, it always checks if the record still meets its schedule criteria before calling its update action!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kU48!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kU48!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 424w, https://substackcdn.com/image/fetch/$s_!kU48!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 848w, https://substackcdn.com/image/fetch/$s_!kU48!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 1272w, https://substackcdn.com/image/fetch/$s_!kU48!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kU48!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png" width="632" height="124" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:124,&quot;width&quot;:632,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11110,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kU48!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 424w, https://substackcdn.com/image/fetch/$s_!kU48!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 848w, https://substackcdn.com/image/fetch/$s_!kU48!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 1272w, https://substackcdn.com/image/fetch/$s_!kU48!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0dd0d35f-681c-4507-9ffe-f565837fd03a_632x124.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Want to resend a specific email? You can add a `:resend` state, and update your trigger to account for that new state</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mWJ1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mWJ1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 424w, https://substackcdn.com/image/fetch/$s_!mWJ1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 848w, https://substackcdn.com/image/fetch/$s_!mWJ1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 1272w, https://substackcdn.com/image/fetch/$s_!mWJ1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mWJ1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png" width="852" height="340" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/548b870d-f826-48b6-baa8-542f613d746d_852x340.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:340,&quot;width&quot;:852,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35612,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mWJ1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 424w, https://substackcdn.com/image/fetch/$s_!mWJ1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 848w, https://substackcdn.com/image/fetch/$s_!mWJ1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 1272w, https://substackcdn.com/image/fetch/$s_!mWJ1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F548b870d-f826-48b6-baa8-542f613d746d_852x340.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Wrapping up</h3><p>As you can see, the Oban-backed strategy is very powerful. However, the other strategies shown can be great starting points, or perhaps they cover the use case that you have well enough on their own.</p><p>These strategies apply to <em>any kind of side effect</em>. We&#8217;re just using emails here because that is such a common requirement. You should now be armed with the tools to navigate the various options in Ash for adding side effects to your actions.</p><h3>What do you think?</h3><p>This is the first hard-core detail-oriented writing I&#8217;ve done here on this Substack. I&#8217;ll be adapting this into a how-to guide in Ash&#8217;s documentation in the future. Do you like this kind of thing? Or do you prefer content on more high level concepts? Let me know in the comments!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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 Zach Daniel! 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[Silos in the Elixir Community]]></title><description><![CDATA[The lines that divide us, for better or for worse]]></description><link>https://www.zachdaniel.dev/p/silos-in-the-elixir-community</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/silos-in-the-elixir-community</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Tue, 17 Sep 2024 15:32:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!sp1P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few years ago, someone asked on the Elixir slack &#8220;Is the Ash project dead?&#8221; Thats how I knew something was wrong.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sp1P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sp1P!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!sp1P!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!sp1P!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!sp1P!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sp1P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp" width="420" height="240" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:420,&quot;bytes&quot;:511140,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sp1P!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!sp1P!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!sp1P!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!sp1P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F404ba758-c84e-46a8-b7ef-03f5b3f0c3ab_1792x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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.zachdaniel.dev/subscribe?"><span>Subscribe now</span></a></p><p>Let's start by answering the question &#8220;Where do Elixir developers hang out?&#8221;. You probably know about a few of these, but very few people are aware of just how many sub-communities there really are. This is certainly not an exhaustive list, and these are not in any particular order.</p><ul><li><p><a href="https://elixirforum.com">Elixir Forum</a></p></li><li><p><a href="https://stackoverflow.com/questions/tagged/elixir">Stack Overflow</a></p></li><li><p>Github Issues &amp; Discussions</p></li><li><p>Slack</p><ul><li><p><a href="https://elixir-lang.slack.com/join/shared_invite/zt-2b90hwr0l-KzkegyzRL1XgmA6Q~CAlIQ#/shared-invite/email">Elixir Slack</a></p></li><li><p><a href="https://erlef.org/slack-invite/erlef">EEF(Erlang Ecosystem Foundation) Slack</a></p></li></ul></li><li><p>Discord</p><ul><li><p><a href="https://discord.com/invite/elixir">Discord</a></p></li><li><p><a href="https://discord.gg/pJWKvXuvzN">Elixir-Tools Discord</a></p></li><li><p><a href="https://discord.gg/w3AXeARR2p">Ash Framework Discord</a></p></li><li><p><a href="https://discord.com/invite/elixir-oasis">Elixir Oasis</a></p></li></ul></li><li><p><a href="irc://irc.libera.chat/elixir">#elixir on irc.libera.chat</a></p></li><li><p>Social Networks</p><ul><li><p><a href="https://x.com/elixirlang">Twitter</a></p></li><li><p><a href="https://mastodon.social/tags/elixir">Mastodon</a></p></li><li><p><a href="https://bsky.app/search?q=%23elixir">Bluesky</a></p></li></ul></li><li><p>Telegram</p><ul><li><p><a href="https://t.me/elixir_formula">Elixir Formula</a></p></li><li><p><a href="https://t.me/elixir_world">Elixir World</a></p></li></ul></li><li><p><a href="https://reddit.com/r/elixir">Reddit</a></p><p></p></li></ul><p>With that information, I bet you know exactly where to go to participate in the community, so we can end the article here, right? Sure.</p><h3>How did this happen?</h3><p>People are on these different platforms for a reason. Twitter is <a href="https://www.bbc.com/news/articles/crkmpe53l6jo">banned in Brazil</a> right now. Many workplaces <a href="https://community.spiceworks.com/t/blocking-discord-in-the-workplace/682550">don&#8217;t allow discord</a>. People have personal reasons. Many don&#8217;t like the politics of twitter. Or the walled garden of Slack/Discord. Or simply want to be in a smaller community that they view as more like themselves, or perhaps more accepting of who they are.</p><p>So this conversation can&#8217;t be about &#8220;taking things away&#8221;, which is a natural first conclusion when you start thinking about this problem. Why don&#8217;t we just choose between Discord &amp; Slack? Combine the communities? Because you&#8217;re going to alienate a large group of people regardless of how you do it.</p><p>Smushing all of these communities together is not a good idea even if we could. Even if everyone was willing, would one &#8220;mega-community&#8221; really make anything better? I find it doubtful. Many people have told me that they appreciate the Ash discord server in part because it is a much smaller group than &#8220;all Elixir developers&#8221;, cutting down the noise. </p><p>This is the &#8220;better&#8221;, in &#8220;for better or for worse&#8221;.</p><h2>So what is the problem then?</h2><h3>Beginners can get lost</h3><p>Where do I go for help? </p><ul><li><p>Google? Well, millions of questions have been answered in non-indexable places like Slack, Discord and IRC. So you won&#8217;t have nearly as much luck as you would here.</p></li><li><p>Stack Overflow? Strangely unpopular among Elixir developers. But there is some good stuff here. You might find what you&#8217;re looking for, but its unlikely.</p></li><li><p>Issue trackers? No! Those are for bug reports with proper reproductions and all the info necessary!</p></li><li><p>Slack? What if the folks who know about the thing you&#8217;re asking about aren&#8217;t <em>in</em> Slack? Or they&#8217;re busy today? </p></li><li><p>How about I search in Slack! Oh&#8230;only the last 10k messages are kept? I guess all that hard work from the community is gone forever then. None of the history is indexed by search engines either.</p></li><li><p>IRC? Same problems.</p></li><li><p>Discord? Same problems. You have unlimited search back here, which is awesome. <em>For now</em>. Who knows what changes discord will make?</p></li><li><p>Right, Elixir Forum then. This is the actual best answer, but that doesn&#8217;t mean that it wouldn&#8217;t have been faster to get help elsewhere. </p></li></ul><h3>The optics aren&#8217;t great</h3><p>As a community, we have to cut a difficult balance. A balance between considering the commercial aspects of what we do and the fun aspects. The Elixir community is a lot of fun to be a part of, and the fact that our direction is not set by corporate overlords is the reason that many of us are here. I, for one, believe it will play out better for our community in the long run.</p><p>With that said, a <em>very </em>large portion of the Elixir community is focused on working with Elixir professionally. We need a healthy job market. We need a healthy image from members that are not a part of our community, to increase adoption. We need things like case studies, success stories that act as a testament to the power of Elixir. </p><p>This stuff isn&#8217;t <em>fun</em>.<em> </em>Its annoying. Half the time it can even feel disingenuous. We are experts; We are aware of the challenges we faced building a thing. It wasn&#8217;t <em>magic</em>. We aren&#8217;t salespeople. But we have to <em>sell</em> it. At least, we do if we want Elixir to continue to be a viable career choice.</p><p>When someone asked if the Ash project was &#8220;dead&#8221;, I realized that for all the <em>benefits</em> I got from having my own discord server (custom roles, as many dedicated channels as I want, low signal/noise ratio for things we cared about) there was also one <em>major </em>drawback. I had created a <em>silo.</em></p><p>I&#8217;ve always thought of Ash as something that could draw new developers to Elixir. This has proven to be true! But if you googled Ash Framework two years ago, you&#8217;d see a smattering of questions on Elixir Forum, a few of my conference talks, and it <em>would not have been enough.</em></p><p>Creating a dedicated space in the Elixir Forum was the best thing we ever did for the Ash community. We still have our discord server, but we encourage questions to be posted in Elixir Forum. Some people are better at this than others. We aren&#8217;t forcing anything on anyone. We meet them where they are at. So all we had to do was make an <em>avenue</em> for participation in a more open community, and we got the benefits. </p><p>The Oban community ended up doing the same thing that we did, and just the other day, the Nerves community announced that they were doing the same. Huzzah! The silos are collapsing!</p><h3>So what do we do?</h3><p>No-one likes to think of the optics. I get that. And the truth is, <em>you don&#8217;t have to</em>. You do you. </p><p>However, if you&#8217;re part of the leadership of this community, or wish to make an active change, I highly implore you to consider the cost of these silos. They make the language look far less active and supported than it actually is. They make it hard for beginners to know where to get help, or to get the best help that they can.</p><p>We&#8217;re talking about this on <a href="https://elixirforum.com/t/is-there-a-feed-with-content-of-the-main-elixir-maintainers/66061">Elixir Forum</a> right now. People have a difficult time getting caught up on the Elixir news, because it happens on a social network they can&#8217;t access. Or because it happens in a silo they don&#8217;t know about.</p><p>Here are some positive impacts that can be made right now:</p><ul><li><p>If you&#8217;re posting awesome content on twitter, like this <a href="https://x.com/josevalim/status/1833536127267144101">awesome video by Jos&#233; Valim on optimistic updates in LiveView</a>, post it on the Elixir Forum too!</p></li><li><p>Alternatively, post it anywhere you&#8217;ve got an RSS feed. Like Substack, or your blog.</p></li><li><p>When in doubt, use Elixir Forum. It&#8217;s an open community. It has excellent SEO. You can subscribe to any part of it as an RSS feed. The posts are automatically sent to twitter even!</p></li></ul><p>Elixir is a growing language. Lets help our newbies, and show the world the kind of traction that is really has!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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.zachdaniel.dev/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[A Day in the Life]]></title><description><![CDATA[A.K.A - How I Get Shit Done]]></description><link>https://www.zachdaniel.dev/p/a-day-in-the-life</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/a-day-in-the-life</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Mon, 16 Sep 2024 15:36:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5NaD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Maintaining and developing <a href="http://ash-hq.org">Ash Framework</a> is essentially my full-time job. Here is what it looks like.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5NaD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5NaD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!5NaD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!5NaD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!5NaD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5NaD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp" width="388" height="388" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:388,&quot;bytes&quot;:368068,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5NaD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!5NaD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!5NaD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!5NaD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4909049-f2a4-4b41-b1b2-a92d243e6ab7_1024x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I occasionally work on our client projects at <a href="http://alembic.com.au">Alembic</a>, something I actually really enjoy doing. Chris McCord <a href="https://www.youtube.com/watch?v=Ckgl9KO4E4M">talks about the benefits</a> of using our own tools in anger, and I completely agree. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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 Zach Daniel! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>I&#8217;ll be focusing here on those days when my time isn&#8217;t spoken for by clients for the majority of the day. I&#8217;m also not focusing on the technical content of my day, but on the mindset and methods I use to Get Shit Done.</p><h2>I have a problem</h2><p>You&#8217;re going to see it soon enough, but the truth is that I have what is effectively a pathological level of concern for the members of the Ash community. My relationship with my work and how I balance it is something that I&#8217;m actively working on transforming. In fact, that is a part of why I&#8217;m writing this newsletter!</p><p>It helps me to write. It makes me feel like my output can be measured in more than bugs fixed and features announced. It gives me an avenue of expression to the users that I spend my days working on behalf of, and makes this all feel that much more like a conversation.</p><p>So write I shall!</p><h2>Wake up</h2><p>The first thing I do in the morning is look at my phone to see what issues/requests have come in overnight. Like before I get out of bed. This is probably the number one thing that I&#8217;d like to change. But every day is so wildly different depending on what sorts of things have come in from users on that day.</p><p>If there is a serious bug, then it takes priority over my feature work. If there are a lot of new people getting started that day, my morning will be filled with conversations helping them get started. If some of my clients have had questions or have requested PR reviews, then that has to happen too. It&#8217;s a very dynamic way to work, something that I both appreciate and that exhausts me.</p><h2>Start the loop</h2><p>I honestly don&#8217;t know if this is something that other people do, but I practically live my life in the loop. The loop is a simple concept, geared towards managing a firehose of incoming work, and helping an anxious programmer feel like they aren&#8217;t leaving anyone hanging. </p><p>I have a list of the <em>kinds </em>of things I have to do each day. Starting with work <em>generating</em> items at the top, and deep/engaging work at the bottom. For example, my list looks something like this:</p><ul><li><p>Check email, Discord, Slack, Reminders, ElixirForum, Bluesky, Twitter</p></li><li><p>Fix serious bugs</p></li><li><p>Answer questions</p></li><li><p>Implement next item on roadmap</p></li><li><p>Announce new features, or write new content</p></li><li><p>Fix minor bugs</p></li></ul><p>When I get to the bottom, I go back to the top. I&#8217;ll skip items if I&#8217;ve done them recently enough that new things shouldn&#8217;t have popped up. My priorities may change from day to day, but it doesn&#8217;t deviate much from this pattern.</p><h3>5-minute rule</h3><p>As I&#8217;m going, if anything comes up that would take less than five minutes to handle, I handle it on the spot, no hesitation. This is one of the main reasons community members get support as quickly as they do. They don&#8217;t get &#8220;filed away for when I have time&#8221;.</p><p>This is actually a commonly occurring rule in productivity systems, but I have one personal change to it that makes all the difference. </p><p>When something comes up that would take <em>more</em> than five minutes to handle, I find <em>any part of it</em> that will take <em>five minutes or less</em> to perform, and do that immediately. For an issue report, this might mean finding some clarifying question that I can ask the reporter that will help me when it comes back up in my loop. For a feature, or a project, this might mean &#8220;identify a few large themes in the request and write them down&#8221; or &#8220;re-summarize the effort in my own words.&#8221;</p><h3>Taking on new work</h3><p>For anything that takes more than five minutes, I will first comment to indicate that I&#8217;m aware of the item if necessary. Then, I&#8217;ll do one of two things:</p><ul><li><p>Mark it as unread. This is an escape valve for when I really just do not have time to consider the item at all.</p></li><li><p>Decide when I&#8217;m going to consider the item again, and push the item off until that time. 9 times out of 10, this means I put a scheduled reminder into Apple Reminders.</p></li></ul><p>When scheduling work, an important part of my mindset is that I&#8217;m not necessarily committing to do it at that time, only to consider doing it at that time. It <em>can</em> be a commitment, i.e in the case of time-sensitive items, but it does not have to be.</p><p>When a scheduled item comes up, I either handle it, or I push it to another time <em>after applying the 5-minute rule</em>. In this way, all the needles get pushed forward at least a little bit whenever they come back up in my loop.</p><h3>Nothing gets lost</h3><p>By operating this way, I ultimately do not miss <em>even a single</em> item that comes up as I&#8217;m working. If I ever load-shed incoming work, I do it consciously. I don&#8217;t miss notifications, emails (inbox zero is the way). If I ever do, it&#8217;s because I didn&#8217;t have something adequately hooked up to my loop (like I wasn&#8217;t watching a GitHub repository I should have been watching) and so it&#8217;s easy to rectify.</p><p>This means confidence for those interacting with or depending on me, and a feeling of control for myself.</p><h3>Context switching is key</h3><p>The way that I work necessitates switching modes often. I go through my loop hundreds of times a day. Sometimes stopping in the middle (at natural break points) of feature work to make sure that all the plates are still spinning. Everything I&#8217;ve read says that context switching is the death of productivity. Either I have a unique ability to context switch, or that isn&#8217;t exactly correct. </p><h2>Close the loop</h2><p>One thing I&#8217;ve found is that it can be very difficult to break out of this loop when it&#8217;s time to shut down. I&#8217;m so used to feeling confident that all my inboxes are cleared. I struggle often with putting my work down at the end of the day. </p><p>Something I&#8217;ve noticed that helps is setting a quit time at the <em>start</em> of the day, instead of trying to do it when you&#8217;re &#8220;done with your work.&#8221; So my loop these days has an item at the top that says &#8220;schedule shutdown time.&#8221;</p><h3>And this is what I do, day in, day out</h3><p>I honestly have no idea how unique this mental model for getting my work done is. Maybe it sounds wildly obvious to those reading it. Maybe everyone has a loop built in, and the fact that I&#8217;ve formalized my own loop a bit is weird. Maybe it takes 763 licks to get to the center of a Tootsie Pop. The world will never know.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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 Zach Daniel! 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[Welcome to my Substack!]]></title><description><![CDATA[A place of magic and mystery &#129668;]]></description><link>https://www.zachdaniel.dev/p/welcome-to-my-substack</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/welcome-to-my-substack</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Mon, 16 Sep 2024 00:48:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3yGT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before I dive in, I&#8217;d like to remind my readers why they might be receiving this in their inbox.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3yGT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3yGT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!3yGT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!3yGT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!3yGT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3yGT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp" width="340" height="340" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:340,&quot;bytes&quot;:151988,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3yGT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 424w, https://substackcdn.com/image/fetch/$s_!3yGT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 848w, https://substackcdn.com/image/fetch/$s_!3yGT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 1272w, https://substackcdn.com/image/fetch/$s_!3yGT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff4857192-bbaf-42ad-a8cb-f066cae1da6a_1024x1024.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It may have been a long time ago, but you signed up for a mailing list on the <a href="http://ash-hq.org">Ash Framework website</a>. I never actually <em>used </em>that mailing list, but I very much intend to use this one.</p><h2>So what are we doing here?</h2><p>From here on, I&#8217;ll be communicating a bit more frequently, and in longer form than my usual tweet announcements. The Ash community continues to grow, and I think it will behoove me to share a bit more of my voice than a <a href="http://hexdocs.pm/ash/changelog.html">changelog</a>, or <a href="https://x.com/ZachSDaniel1/status/1833291409023029616">simple feature announcements</a>.</p><p>What will I be writing about, you ask? Why, anything and everything! While you may know me from my obsession with shipping code, I am, in fact, more than a feature-shipping machine. There are lots of things I&#8217;d like to talk to you all about. From Ash &amp; Elixir, to things that I find personally interesting, to open source &amp; ethics.</p><p>I&#8217;d like to hear from you, too! Click below to tell me about yourself, and what you&#8217;d like to get out of this news letter.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/survey/780765?token=&quot;,&quot;text&quot;:&quot;Tell me about yourself&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.zachdaniel.dev/survey/780765?token="><span>Tell me about yourself</span></a></p><h2>Is that really it??</h2><p>Not wanting to leave you all bored from a simple welcome email, let&#8217;s dive into our first topic! &#128293;</p><h2>Igniter</h2><p>My latest project, and where a lot of my energy is going these days, is called <a href="http://hexdocs.pm/igniter">Igniter</a>. Igniter is a code generation and project patching framework. The level of DX that it provides for those writing and using code generators and installers in Elixir is, in my opinion, unparalleled.</p><p><a href="https://x.com/RootCert">Christian Alexander</a> posted an <a href="https://www.youtube.com/watch?v=gpaV4bgEG-g&amp;t=1s">awesome introductory video</a> the other day. I was really pleased to see such a well made and informative introduction to igniter. Check it out, as well as <a href="https://www.youtube.com/@CodeAndStuff">his other content</a> if you haven&#8217;t!</p><h2>Why igniter?</h2><h3>Generators suck</h3><p>It was high time to add generators and installers for our Ash packages. The setup was <em>far<strong> </strong></em>too manual. With that said, I&#8217;ve always hated code generators as a general pattern. I&#8217;ve avoided them for years. </p><p>I was not willing to write a simple &#8220;copy templates to files&#8221; generator for new Ash projects. We needed to provide a first class experience, and build on a solid tool.</p><p>Some of the things that igniter does to provide a high quality experience:</p><ul><li><p>AST based patching of code</p></li><li><p>Automatic discovery of installers</p></li><li><p>Composable generators</p></li><li><p>Diffs and confirmation of changes</p></li></ul><h2>DX is what Elixir needs</h2><p>As someone who has been a member of the Elixir community for almost 10 years now, I know that the DX of Elixir is unparalleled. However, there are a class of things that are highly visible when new people join our community.</p><ol><li><p>Our language server is lacking</p></li><li><p>Getting started is hard</p></li></ol><h3>Language Servers</h3><p>This is not news to anyone, really, and I won&#8217;t harp on it here. The language server teams have worked hard at improving this problem, and I think that people are often far too hard on them. High quality language servers can be <em>multi-year projects</em> for <em>multiple full time engineers</em>. The most important news here is the formation of the <a href="https://elixir-lang.org/blog/2024/08/15/welcome-elixir-language-server-team/">official language server team</a>. I was <em>giddy</em> when I heard the news!</p><h3>Getting started</h3><p>The main way that people enter into the Elixir ecosystem is via some kind of toolchain or framework. For instance, Phoenix, Ash, NX, Livebook, etc. I think we can drastically underestimate the amount of people who will bounce off of the Elixir ecosystem due to even small amounts of friction at the outset.</p><p>If we can give them a <em>seamless</em> getting started experience, with installers that allow them to incrementally adopt new parts of the Elixir ecosystem, with a simple, easy-to-remember CLI, then we can help smooth the way for these new folks to join our community and help bring Elixir out of its niche and put it in its rightful place.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WJQi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WJQi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 424w, https://substackcdn.com/image/fetch/$s_!WJQi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 848w, https://substackcdn.com/image/fetch/$s_!WJQi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 1272w, https://substackcdn.com/image/fetch/$s_!WJQi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WJQi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png" width="1456" height="664" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:664,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:178568,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WJQi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 424w, https://substackcdn.com/image/fetch/$s_!WJQi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 848w, https://substackcdn.com/image/fetch/$s_!WJQi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 1272w, https://substackcdn.com/image/fetch/$s_!WJQi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3bd6560-4c5b-4d0f-909d-d93a47d008ca_1694x772.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>So where is it headed?</h2><p>By the time Igniter has become what I know that it can become, it will be like <code>npm install on steroids. It will be like `brew install` but for installing libraries into your app. Your one stop shop. Additionally, it will overhaul existing generators to have a better UX, and allow for writing a whole new class of tasks with ease, like upgrade scripts and project transformers. </code></p><p><code>For one such example, see</code> <a href="https://github.com/elixir-gettext/gettext/blob/main/CHANGELOG.md#migration-with-igniter">mix igniter.update_gettext</a>, a magic one-liner to modify your project to resolve a warning from gettext.</p><h2>Thats it folks!</h2><p>Thank you all for reading, and I hope to continue to awe and amaze with more rambles for many years to come. Don&#8217;t forget to take the survey! I&#8217;d love to hear from you.</p><p>Happy hacking &#128526;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/survey/780765?token=&quot;,&quot;text&quot;:&quot;Tell me about yourself&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.zachdaniel.dev/survey/780765?token="><span>Tell me about yourself</span></a></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.zachdaniel.dev/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 Zach Daniel! 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[An Incremental Approach to Declarative Design]]></title><description><![CDATA[Practical tips to adopt Declarative Design in your every day code.]]></description><link>https://www.zachdaniel.dev/p/incremental-declarative-design</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/incremental-declarative-design</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Fri, 25 Dec 2020 01:45:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!uzrk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Declarative Design sits at the core of my largest project, <a href="http://ash-hq.org">Ash Framework</a>.</p><p>It is my belief that, however hyperbolic, Declarative Design is the key to the future of software. I didn't invent it, nor do I count among the early pioneers of it. In fact, while this may be the first time you've thought about it specifically as "Declarative Design", you've almost certainly been exposed to it many times already. </p><p>If you've used SQL, HTML or CSS, you've worked with declarative languages. So instead of trying to pitch you on the concepts presented in Ash, I'd like to provide a small example of how you can add Declarative Design to your code-base today and benefit from it immediately.</p><p>Before we get started it is important to note that, if you are building any kind of software application at all, you are building an abstraction of a domain (a.k.a problem space, business use case). This single fact means that your system will be far more&nbsp;_internally consistent_&nbsp;(each part of itself similar to the other) than it will be&nbsp;_consistent with external systems_. The high level constraints on your system inevitably shape every subsystem within it. </p><p>While "premature abstraction" can be a serious problem, &#8220;late abstraction&#8221; can be just as serious. Declarative Design is the method by which you side-step the problems presented by imperative styles of abstraction.</p><p>How do we side-step these problems? We <em>extract the data</em>, instead of <em>abstracting the code.</em></p><h2>Example</h2><p>These examples are written in <a href="https://elixir-lang.org">Elixir</a>, but they are primarily pseudo-code/should be easily readable by any programmer. A bunch of code is left out, because the point is the structure/changes we make, not the minutia of each operation.</p><p>We'll start small, with a module that does some simple work of taking some data provided by an API and creating a corresponding record for that data.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uzrk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uzrk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 424w, https://substackcdn.com/image/fetch/$s_!uzrk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 848w, https://substackcdn.com/image/fetch/$s_!uzrk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 1272w, https://substackcdn.com/image/fetch/$s_!uzrk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uzrk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png" width="546" height="404.768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:556,&quot;width&quot;:750,&quot;resizeWidth&quot;:546,&quot;bytes&quot;:72247,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uzrk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 424w, https://substackcdn.com/image/fetch/$s_!uzrk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 848w, https://substackcdn.com/image/fetch/$s_!uzrk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 1272w, https://substackcdn.com/image/fetch/$s_!uzrk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1001f64-42e8-480b-ba78-c7427c80d1f0_750x556.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We&#8217;ve shipped the above. Our service is creating data, everything is going swell. A few days later we get a call from a customer saying that his post creation requests are failing, and others are taking a very long time to complete. </p><p>So let&#8217;s create a function that will log the time each operation takes, and report any failures. Naturally we should do this for each of our operations.</p><p>Let&#8217;s follow the conventional wisdom of not abstracting too early, and take the obvious path.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HXhT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HXhT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 424w, https://substackcdn.com/image/fetch/$s_!HXhT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 848w, https://substackcdn.com/image/fetch/$s_!HXhT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 1272w, https://substackcdn.com/image/fetch/$s_!HXhT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HXhT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png" width="528" height="435.4871794871795" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:772,&quot;width&quot;:936,&quot;resizeWidth&quot;:528,&quot;bytes&quot;:124744,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HXhT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 424w, https://substackcdn.com/image/fetch/$s_!HXhT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 848w, https://substackcdn.com/image/fetch/$s_!HXhT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 1272w, https://substackcdn.com/image/fetch/$s_!HXhT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc758266b-d110-4e71-bdd3-e3a43c383ca3_936x772.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Update shipped, it&#8217;s doing what it is supposed to, we're seeing metrics and log messages, and we were able to use that information to solve our customer's issue. </p><p>A few days later, we find out that there are some users that are creating bad data. We aren&#8217;t tracking who is making what changes, so let&#8217;s add some auditing code. We need to accept the user as an argument, and create an audit log with the result of each operation.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N_6S!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N_6S!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 424w, https://substackcdn.com/image/fetch/$s_!N_6S!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 848w, https://substackcdn.com/image/fetch/$s_!N_6S!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 1272w, https://substackcdn.com/image/fetch/$s_!N_6S!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N_6S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png" width="532" height="474.8073022312373" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:880,&quot;width&quot;:986,&quot;resizeWidth&quot;:532,&quot;bytes&quot;:164208,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!N_6S!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 424w, https://substackcdn.com/image/fetch/$s_!N_6S!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 848w, https://substackcdn.com/image/fetch/$s_!N_6S!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 1272w, https://substackcdn.com/image/fetch/$s_!N_6S!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F93bb9f67-4139-4d8a-9815-3a064ebf707d_986x880.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Alright, this is out in the world and with these audit logs we&#8217;ve found and banned the bad actors. </p><p>Our next requirement comes in. Apparently, we&#8217;d like to give the interns access to the system. They should be able to create posts, but not people or organizations. </p><p>Well, this should be pretty straightforward!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MoSk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MoSk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 424w, https://substackcdn.com/image/fetch/$s_!MoSk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 848w, https://substackcdn.com/image/fetch/$s_!MoSk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 1272w, https://substackcdn.com/image/fetch/$s_!MoSk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MoSk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png" width="552" height="632.0941176470589" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1168,&quot;width&quot;:1020,&quot;resizeWidth&quot;:552,&quot;bytes&quot;:204113,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MoSk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 424w, https://substackcdn.com/image/fetch/$s_!MoSk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 848w, https://substackcdn.com/image/fetch/$s_!MoSk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 1272w, https://substackcdn.com/image/fetch/$s_!MoSk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3704e38-264c-40e3-9c6b-bc37a0891c7f_1020x1168.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>So what&#8217;s wrong with this code?</h2><p>Honestly? Nothing. If this was your entire app, just these three functions, <em>do not change this code</em>. The problem is that the majority of our applications are considerably more operations like this. So with that lens, there are the three primary problems.</p><h3>Duplication</h3><p>This is the classic problem embodied with principles like <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>. We don&#8217;t want to repeat ourselves because that can make changing the way our system work very difficult. We&#8217;d have to change a lot of places, and there is risk that we will do it wrong in some of them. Or that we will forget to do it in some of them.</p><h3>Hidden Divergence</h3><p>The *real* problem, however, is the <em>opportunities for hidden divergence.</em> These operations are <em>almost </em>the same. But not quite! They all take a <code>user</code> argument, but they don&#8217;t all have rules that involve the user.</p><p>These opportunities for misunderstanding are very dangerous.</p><h3>We&#8217;re leaving a lot on the table</h3><p>You&#8217;ll see what I mean shortly. Ultimately, we could do <em>more</em> with this code, effectively <em>for free. </em>It just has to be written differently. Let&#8217;s take a look. I&#8217;m just going to skip to the end and show you what I&#8217;d suggest the &#8220;right answer&#8221; looks like.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S6sw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S6sw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 424w, https://substackcdn.com/image/fetch/$s_!S6sw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 848w, https://substackcdn.com/image/fetch/$s_!S6sw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!S6sw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S6sw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png" width="548" height="801.5843137254902" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1492,&quot;width&quot;:1020,&quot;resizeWidth&quot;:548,&quot;bytes&quot;:228107,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S6sw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 424w, https://substackcdn.com/image/fetch/$s_!S6sw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 848w, https://substackcdn.com/image/fetch/$s_!S6sw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!S6sw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b89eb85-48d6-4a48-b499-2626f3367d86_1020x1492.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>So let's break down the benefits here. By separating this logic into two components, the "declaration", i.e the &#8220;what&#8221;, and the "engine", i.e the &#8220;how&#8221;. The amount of downstream good that comes from this kind of design is impossible for me to overstate.</p><p>1. Notice how legible the description is? I bet you could show that directly to a non technical person and they would understand "what" your code does, without having to know "how" it does it.</p><p>2. When you need to change something, you have a great starting point for that discussion. If you're changing your description, that means you're changing the <em>domain</em>. If you need to change the engine, you are&nbsp;changing&nbsp;the <em>method</em>.</p><p>3. Someone else can come along and rewrite the engine, leaving the description intact. This guiding force can allow for extremely easy refactors, potentially even in a different programming language entirely.</p><p>4. If I want to add a new operation, say&nbsp;`create_comment`&nbsp;it is effectively a triviality, and it can be configured with all the goodness we've built into our description.</p><p>5. This description is static, and can be used to power other things! You cold generate a markdown file, or a diagram from these descriptions. This is far more useful than you may realize, and we have all kinds of tools along these lines in Ash.</p><h2>In closing</h2><p>As you can see, we don't even really care that much about the procedural code anymore. We can discuss changes to the underlying behavior&nbsp;<em>solely with the description</em>. </p><p>This is your DSL, or "domain specific language". DSLs don't have to be confusing or magic. They don't have to use macros. A DSL could just be a map, or nested keyword lists like we used above.</p><p>Declarative Design can work at many levels across your system. It can be the driver behind complex system flows, and it can also help with abstracting and encapsulating code on a smaller scale. </p><p>Ultimately, in my experience, Declarative Design <em>incurs&nbsp;very little</em> cost or risk. It increases our leverage and flexibility, while keeping our code simple and understandable.</p>]]></content:encoded></item><item><title><![CDATA[Learning How to Learn Japanese]]></title><description><![CDATA[The tale of my early journey through &#26085;&#26412;&#35486;, and some tips for &#26085;&#26412;&#35486; learners.]]></description><link>https://www.zachdaniel.dev/p/learning-how-to-learn-japanese</link><guid isPermaLink="false">https://www.zachdaniel.dev/p/learning-how-to-learn-japanese</guid><dc:creator><![CDATA[Zach Daniel]]></dc:creator><pubDate>Tue, 12 May 2020 03:02:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F6vw!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F03109cde-c295-4f14-8b48-efd49c1634de_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Update:</h2><p>As of 2023, my methods have changed a bit. I still use bunpro, but have traded wanikani and kamesame for <a href="https://jpdb.io">JPDB</a>.</p><div><hr></div><p><strong>tl;dr</strong> - This essay is broken into four sections: 1) why I&#8217;m learning Japanese, 2) some basics about Japanese alphabets, 3) what makes it a hard language to learn, and 4) the tools I&#8217;m using to learn it. If you just want to know about that last bit feel free to scroll down to the bottom.</p><p>I've always wanted to learn another language. For years, I would pick up Duolingo and mess around with it for a few weeks before moving on to something else. Then, a little over a year ago, my best friend decided that he wanted to learn Japanese. While I&#8217;d love to say that being able to speak Japanese has been a lifelong dream, my motivation is slightly less pure. Specifically, I took the fact that Japanese is, by some accounts,&nbsp;<a href="https://effectivelanguagelearning.com/language-guide/language-difficulty/">the most difficult language</a>&nbsp;an English speaker can attempt to learn, as a personal challenge.</p><p>This changed the shape of my learning journey. Now, instead of trying to optimize for short-term usage, I was headed down a path that would take years to complete. Knowing that was surprisingly&nbsp;_helpful_&nbsp;with my motivation, as it changed my whole perspective around comprehension, ensuring the time took to learn new things didn't get me down. I was finally equipped for my language journey: I had motivation, a partner, and time, and that is all you need. Or so I thought.</p><p>If you're already familiar with the Japanese, you can probably skip this section.</p><p>I'll take a brief interlude to explain some foundations. There are three character sets, two of which are phonetic (like the English alphabet), meaning that they each have a specific sound. The first is called <a href="https://en.wikipedia.org/wiki/Hiragana">hiragana</a>(&#12402;&#12425;&#12364;&#12394;) and is the most basic/ubiquitous of the three. The second is called&nbsp;<a href="https://en.wikipedia.org/wiki/Katakana">katakana</a>(&#12459;&#12479;&#12459;&#12490;) and generally has more specialized usage. For every hiragana, there is a corresponding katakana. They are most often used to represent "loan words" like &#12496;&#12473;(basu) for "bus" or &#12497;&#12531;(pan) for "bread" (from Portuguese). Having multiple phonetic alphabets sounded very strange to me at first, until I realized that English&nbsp;<em>also</em>&nbsp;has two (not counting cursive)! Look at each letter in "bard" compared to "BARD" to see what I mean.</p><p>The final character set,&nbsp;<a href="https://en.wikipedia.org/wiki/Kanji">Kanji</a>(&#28450;&#23383;), is the one that most people have heard of. It is also one of the most daunting aspects of learning Japanese. There are roughly 50,000 Kanji, but the vast majority of them are no longer in use. The Japanese government maintains a set of&nbsp;<a href="https://en.wikipedia.org/wiki/List_of_j%C5%8Dy%C5%8D_kanji">2,136 Kanji</a>&nbsp;that must be taught at school, but most educated Japanese adults know somewhere from 3-4,000. If you work in a specialized field like medicine, or if you are an academic, that number can go as high as 6,000! (hearsay, can&#8217;t find a source on these numbers) I'll talk more about Kanji and their challenges a bit further on.</p><p>Grammatically, Japanese is about as different as you can get from English. The sentence structure is so different that you essentially have to think in reverse (some resources even&nbsp;<a href="http://www.textfugu.com/season-1/japanese-grammar-with-yoda/">teach the basics with Yoda</a>). As you learn more advanced/casual grammar, you find out that things can go in pretty much whatever order you want. This does not help in the slightest. Prepositions (in, at, on) in English are post-positioned in Japanese and have little in common. Plurality is complicated; In English, "book" is unequivocally singular. In Japanese, &#26412;(hon), isn't plural or singular, plurality is indicated by context, or by adding qualifying words. I could go on, but I say all this only to explain that learning Kanji isn't the only barrier involved in learning Japanese.</p><h3>Back to the topic at hand</h3><p>It became clear to me pretty quickly that Duolingo just wasn't going to cut it. The concepts didn't map well to the Japanese language and, in all honesty, I think Duolingo's framework just isn't challenging enough in general. This realization started my search for better tools. I had learned that multiple-choice/drag and drop questions are not an effective way to study languages. You need to be "producing" and "translating". Additionally, to learn Japanese you need to use tools that are tailored to Asian languages, or better yet the Japanese language itself. These two conditions knock out a lot of the most popular contenders like Duolingo, and Memrise. I'm not suggesting that those tools don't have value, or that they aren't a good place to start, but that there are more effective tools out there.</p><p>I'll spare you the whirlwind tour of every other tool that I tried and ultimately cast aside and skip ahead to the good stuff. What I ultimately discovered is that, at least for Japanese, you need to front-load Kanji and vocabulary. I've heard many people talk about this, and it is clear that they know it is true, but have trouble articulating&nbsp;_why_&nbsp;it is true. Luckily, I think I'm at a point where I can explain the issue. Keep in mind, this is not meant to discourage, only to explain why trying to just dive into Japanese probably won't get you very far.</p><p>You can learn to "read" English, with its relatively simple phonetic alphabet in a matter of days. Your pronunciation will often be wrong, and you certainly won't know what all the words mean, but you can turn&nbsp;_symbols_&nbsp;into&nbsp;_sounds_&nbsp;from an early stage. What this means is that, generally speaking, trying to remember a word that you&nbsp;_see_&nbsp;is the same as remembering a word that you&nbsp;_hear_. This same parallel isn't true for Japanese, because of Kanji. It typically takes&nbsp;_at least_&nbsp;a year, and typically longer, for an adult to learn the Joyo Kanji (what Japanese children learn in school). If you're presented a word that contains a Kanji that you've never seen before, there is no good way to know how it sounds. There are some patterns/tricks you can use to make decent guesses but this method is not reliable. This prevents you from trying to remember if you've ever "heard" this new word before. Worst of all, if you can figure out the&nbsp;_meaning_&nbsp;of this new word from context, you still won't know how to&nbsp;_say_&nbsp;that word to someone else.</p><p>To put this in context, there is a site called NHK Easy News that presents a simplified version of Japanese news articles. I know 1000 kanji currently, and that represents ~90% of the Kanji that they use on NKH Easy News. That may sound like a lot but having to stop on every 10th word to look it up, and not being able to turn these unknown words into sounds to help you remember/let you access your auditory memory makes trying to read without a really good grasp of Kanji&nbsp;_extremely_&nbsp;tiring. The thing I didn't mention yet: "Knowing" a kanji doesn't mean you know how to say it in every context. For example, the Kanji "&#20154;" in "&#20154;&#39006;", "&#19968;&#20154;", "&#33464;&#20154;" is read differently for each (jin, ri, nin)! So I know 90% of the Kanji, but do I know 90% of all of the ways they use Kanji? Probably not.</p><p>Again, this wasn't meant to discourage you, but to show the merits of this approach.</p><h3>My Tools</h3><p>I'm still just barely intermediate at Japanese but I believe this "stack" is going to take me well into the realm of high-intermediate/advanced, and give me an excellent foundation to continue my learning from. The magic in all of these tools is that they use an SRS or "Spaced Repetition System", that is designed to quiz you on things that you've learned&nbsp;_just before_&nbsp;you forget them. You'll be amazed at how much you can stuff into your brain using an SRS.&nbsp;_All_&nbsp;of the tools I use are based around an SRS. Prioritize these tools in descending order. The workflow is simple: If you have&nbsp;_any_&nbsp;pending reviews or lessons in a higher priority one, do those first. Get back to the other tools if/when you have time.</p><h3><a href="https://www.wanikani.com/">WaniKani</a></h3><p>WaniKani is a system that teaches you most of the Joyo Kanji, and ~6000 vocabulary words in an order tailored to English speaking adults. Their website will explain much better than I could. Wanikani is very much a "point and shoot" solution and it works wonders. Do your lessons when you have time, and do your reviews when they come up, and your Kanji and vocabulary knowledge will skyrocket.</p><h3><a href="https://www.kamesame.com/">KameSame</a></h3><p>WaniKani doesn't do everything. Specifically, it doesn't present you with the English translation of a vocabulary word and have you provide the Japanese word with the same meaning. Luckily, a tool was developed that integrates with WaniKani to provide exactly that. This takes your vocabulary learning to the next level. Just using WaniKani will set you up well for reading/listening, but with KameSame, you'll find yourself able to locate Japanese words on demand, which is (naturally) crucial for speaking.</p><p>Since I started using it, the creator has added a whole host of tools that will make it an extremely useful tool to have in your arsenal, even after you've completed WaniKani. This is one to keep your eye on. Unlike WaniKani, you add lessons at your own pace here with no real cap, so be careful not to get overzealous.</p><h3><a href="https://bunpro.jp/">Bunpro</a></h3><p>![[BunproExample.png]]</p><p>I said Kanji/Vocab&nbsp;_first_&nbsp;but not&nbsp;_only_. Bunpro is an amazing tool for learning grammar via practice. I've never seen anything quite like it, but it embodies the SRS system even while presenting you with different variations of the grammar you are reviewing. In the same way that KameSame will amp up your word production, using Bunpro for a couple of months will have you expressing ideas and building sentences that aren't just "subject-object-verb".</p><h4>Sources</h4><p>https://www.fluentu.com/blog/japanese/japanese-sentence-structure-patterns/</p><p>https://www.sljfaq.org/afaq/how-many-kanji.html</p>]]></content:encoded></item></channel></rss>