<?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[Baby CTO]]></title><description><![CDATA[Leading Tech, People, and Profit: Reflections from a Decade as a Startup CTO.]]></description><link>https://www.baby-cto.com</link><image><url>https://substackcdn.com/image/fetch/$s_!u3-p!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4c9d8fc-b387-47a4-b77f-c2aa0a303dc7_619x619.png</url><title>Baby CTO</title><link>https://www.baby-cto.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 05 May 2026 11:57:31 GMT</lastBuildDate><atom:link href="https://www.baby-cto.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Rémy]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[babycto@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[babycto@substack.com]]></itunes:email><itunes:name><![CDATA[Rémy]]></itunes:name></itunes:owner><itunes:author><![CDATA[Rémy]]></itunes:author><googleplay:owner><![CDATA[babycto@substack.com]]></googleplay:owner><googleplay:email><![CDATA[babycto@substack.com]]></googleplay:email><googleplay:author><![CDATA[Rémy]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Documentation Archaeology: How to Extract Knowledge from Abandoned Codebases with AI]]></title><description><![CDATA[Developers are no strangers to being thrown in a wild project where their ability to understand technical debt will be key to their survival and mental health. LLMs are amazing tools for this use-case]]></description><link>https://www.baby-cto.com/p/documentation-archaeology-how-to-with-ai-llm</link><guid isPermaLink="false">https://www.baby-cto.com/p/documentation-archaeology-how-to-with-ai-llm</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sat, 02 Aug 2025 09:42:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/99fa6ac8-90b4-41c4-9de9-1c49cdfcca15_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You need to work on a legacy project. The engineer who knew all about it left the company a year ago. Because the deadline was too tight, they didn&#8217;t take time to write a documentation. They also didn&#8217;t take a step back on the architecture and simply piled up technical debt. Welcome to what is essentially the digital version of Man versus Wild!</p><p>The good news is: this is a strong use-case for generative AI. Many of you will have strong reservations against clankers, but the general rule of thumb with LLMs is that they are good to make something long shorter.</p><p>More specifically, if you feed them some code they will perfectly understand what it does and most likely even why it does it. It also has strong knowledge of all business areas, so anything that isn&#8217;t pure company jargon should be picked up as well.</p><p>In this article, we will explore the less obvious techniques that will give you superhuman abilities to jump into any project that you have never seen before.</p><p></p><p><em>tldr/spoilers:</em></p><pre><code><em>pfff src/**/*.py | llm -m 'gemini-2.5-pro' -s 'Please write a complete documentation of this project. I want a high-level overview of the main user flows. For each flow, generate proper Mermaid diagrams explaining the communication between all the different parties. Then go into the detail of each flow and explain the specific business decisions taken, edge cases, special rules, etc. For each step of the flow, tell me roughly where to look in the code in case I want to change something.'</em></code></pre><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Sounds good? More ideas like this in future newsletters!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><h1>Workflow setup</h1><p>We&#8217;ll use two main tools for this:</p><ul><li><p><a href="https://pypi.org/project/llm/">llm</a> from <a href="https://simonwillison.net/">Simon Willison</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> gives a great CLI interface to various LLMs of the market</p></li><li><p><a href="https://pypi.org/project/pfff/">pfff</a> from this author, which is simply a way to generate a context with source code in and pipe it into <code>llm</code></p></li></ul><p>Given that they are both Python tool, I can only recommend to use <a href="https://docs.astral.sh/uv/getting-started/installation/#shell-autocompletion">uvx</a> alongside with your shell&#8217;s aliasing system.</p><p>For <code>fish</code> users, that would be:</p><pre><code>alias -s llm='uvx --with llm-gemini --with llm-claude-3 llm'
alias -s pfff='uvx pfff'</code></pre><p>For <code>bash</code>, add to your <code>~/.profile</code> (or the relevant file to your configuration):</p><pre><code>alias llm='uvx --with llm-gemini --with llm-claude-3 llm'
alias pfff='uvx pfff'</code></pre><p>Note how we add <code>llm-gemini</code> and <code>llm-claude-3</code> as dependencies to llm. This is because there are <a href="https://llm.datasette.io/en/stable/plugins/directory.html">many plugins</a> for many providers.</p><p>If you are going to get only one plugin, you should get <code>llm-gemini</code>. This is by far the most useful LLM for the task at hand for a very simple reason. While most top-of-line LLMs have the same exact capabilities, Gemini shines with a 1 million token context window. This is big enough to fit a lot of entire codebases, and this will come in handy.</p><p>Once the plugin is installed, reach to <a href="https://aistudio.google.com/">Google&#8217;s AI Studio</a> to grab an API key then run:</p><pre><code>llm keys set gemini</code></pre><p>Once this is done, you should be able to run something through Gemini, for example:</p><pre><code>&#10095; echo "What is the answer to Life, the Universe and Everything? Give me the answer in JSON and only JSON." | llm -m gemini-2.5-pro
```json
{
  "question": "What is the answer to the ultimate question of Life, the Universe and Everything?",
  "answer": 42
}
```</code></pre><p>From this point on, you&#8217;re ready to go!</p><p>As a bonus however, you can have a look at the following tools:</p><ul><li><p><a href="https://mermaid.js.org/">Mermaid</a>, a lib/tool for diagrams embeddable in Markdown (and supported by GitHub).</p></li><li><p><a href="https://typora.io/">Typora</a>, a nice desktop Markdown editor, which also happens to support Mermaid. Use any editor you want of course, but make sure to have one at hand for the rest of the article.</p></li></ul><h1>Project documentation</h1><p>The LLM being a translation system, we often use it to translate a specification into code, with more or less effect. But on the other hand the code <em>is</em> the ultimate specification, which is fairly easy to translate back into English.</p><h2>Good documentation</h2><p>In order to get something useful, you first need to understand what it is that you seek.</p><p>A good documentation takes you through a story. Not of a princess sleeping in the highest room of the highest tower, but of the various user and data flows that compose the application. A transverse view if you prefer.</p><p>Apart from obscure Doxygen-generated documentations, all popular open source code essentially gives you a set of things:</p><ul><li><p>A &#8220;Getting Started&#8221; guide, whose job is to get you doing something useful within 3 minutes, beyond which point you would lose patience and try another tool</p></li><li><p>A set of &#8220;Tutorials&#8221; or &#8220;Guides&#8221;, which will cover specific use-cases</p></li><li><p>And the &#8220;Reference&#8221; that goes into the nitty gritty details of how individual functions or pieces of function work</p></li></ul><p>The &#8220;Getting Started&#8221; does not usually make sense in a corporate project, given that it has one instance and that&#8217;s it. It&#8217;s already running, you can observe it, not a problem.</p><p>The &#8220;Reference&#8221; well, you will see later but essentially that is not the biggest help at the moment.</p><p>Which leaves you with the topic-centric &#8220;Guides&#8221;. This is what you&#8217;re going to look at generating. What you want to know is, for each &#8220;story&#8221;:</p><ul><li><p>Who speaks to whom in which order. This is what <a href="https://en.wikipedia.org/wiki/Sequence_diagram">sequence diagrams</a> are for, and they are <a href="https://mermaid.js.org/syntax/sequenceDiagram.html">entirely supported</a> by Mermaid</p></li><li><p>Why this exists in a first place</p></li><li><p>Where to find it in the code</p></li><li><p>What are important implementation details that you should be aware of</p></li></ul><p>All you need to do to get this, is to ask :)</p><h2>From scratch</h2><p>Let&#8217;s imagine that at this point, you have no useful documentation. Provided that your project is reasonably small (less than about 100k lines of code) and managed in Git, the first thing you need is to figure a way to list all useful code files.</p><p>A very obvious approach might be something like:</p><pre><code>ls src/**/*.py</code></pre><p>You might otherwise want to look at all the non-binary files in Git:</p><pre><code>git ls-tree -r --name-only HEAD | xargs -I{} sh -c 'git show HEAD:"{}" | grep -Iq . &amp;&amp; echo "{}"'</code></pre><p>You are doing an important job of curating the context for the LLM: picking the right files, as exhaustive as possible, without also throwing huge useless content, confusing or contradictory information, etc.</p><p>In the next part we&#8217;ll be piping this into the LLM and you&#8217;ll start seeing results. If you are happy with the results it&#8217;s great, otherwise you might want to come back and revise the list of files to make it more relevant and/or try to make it fit into the context window if you exceeded it.</p><p>But don&#8217;t overthink it. Do something quick and dirty first. If you like it, go to the next step. And come back only if it fails.</p><p>That&#8217;s where <code>pfff</code> comes into action. It&#8217;s a very small tool whose sole purpose is to print the content of all the files you provided, alongside with their name so that the LLM can get a sense of the project&#8217;s structure.</p><p>Try it out:</p><pre><code>pfff src/**/*.py</code></pre><p>You should end up with your terminal full of your source code. That&#8217;s what you will be sending to the LLM.</p><p>Now let&#8217;s send it with the question:</p><pre><code>pfff src/**/*.py | llm -m 'gemini-2.5-pro' -s 'Please write a complete documentation of this project. I want a high-level overview of the main user flows. For each flow, generate proper Mermaid diagrams explaining the communication between all the different parties. Then go into the detail of each flow and explain the specific business decisions taken, edge cases, special rules, etc. For each step of the flow, tell me roughly where to look in the code in case I want to change something.'</code></pre><p>Adjust the prompt if needed, this one should give you a good first draft. You will receive in the output a long Markdown file containing the long-lost documentation of your project!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kfuz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kfuz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 424w, https://substackcdn.com/image/fetch/$s_!kfuz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 848w, https://substackcdn.com/image/fetch/$s_!kfuz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 1272w, https://substackcdn.com/image/fetch/$s_!kfuz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kfuz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png" width="648" height="453.95604395604397" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1020,&quot;width&quot;:1456,&quot;resizeWidth&quot;:648,&quot;bytes&quot;:224958,&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.baby-cto.com/i/169826783?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.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_!kfuz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 424w, https://substackcdn.com/image/fetch/$s_!kfuz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 848w, https://substackcdn.com/image/fetch/$s_!kfuz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 1272w, https://substackcdn.com/image/fetch/$s_!kfuz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f2c272d-25e0-4b73-b59f-0fa4db6411ef_1975x1384.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Auto-generated documentation for the <a href="https://github.com/cloud-hypervisor/fuse-backend-rs">fuse-backend-rs</a> open source project, which does exactly what I want but whose documentation is still a bit lacking</figcaption></figure></div><p>Copy/paste it into your favorite Markdown editor, you should be able to see all the lovely Mermaid flows and explanation of what is happening under the hood.</p><h2>Keeping the documentation up-to-date</h2><p>What is fantastic with this process is that you can also use it to keep the documentation up-to-date. Nothing easier:</p><pre><code>pfff src/**/*.rs README.md Cargo.toml | llm -m gemini-2.5-pro -s 'Give me an updated version of the README which reflects the state of the code'</code></pre><p>You can integrate other ideas into your prompts, depending on the expected results:</p><ul><li><p>&#8220;Fix all the docstrings that no longer match what the code actually does, or those who are incomplete. Do not rewrite text uselessly, only change things that need changing. Only give me the changed bits.&#8221;</p></li><li><p>&#8220;Compare the documentation with the current state of the code. Add sections that do not exist yet and adjust existing sentences that are inconsistent with the reality of the code. Avoid minor adjustments. Only give me the changed bits.&#8221;</p></li></ul><h2>Figuring the why</h2><p>More often than not you will encounter functions who remain mysterious to you. The previous concepts can be laser-focused onto a specific part of the code. For example, you&#8217;re trying to understand how something specific works in the Linux kernel, which is millions of code thick. From the kernel&#8217;s root folder:</p><pre><code>pfff fs/{ext4,fuse}/**/*.c | llm -m gemini-2.5-pro -s "The FUSE system has a lookup count system. From the implementer's point of view, what should I know? And which opcodes affect it?"</code></pre><p>And there you go. A straight answer from one of the most massive pieces of code that you will ever see.</p><h1>Debugging</h1><p>Another way LLMs are surprisingly efficient is in the unfolding of bugs. That one is not fool-proof, but you can still get very interesting results that will certainly help you to get going.</p><p>Let&#8217;s say that you have a weird bug. You open up your network inspector and grab the query that seems to be the issue:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CPBq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CPBq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 424w, https://substackcdn.com/image/fetch/$s_!CPBq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 848w, https://substackcdn.com/image/fetch/$s_!CPBq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 1272w, https://substackcdn.com/image/fetch/$s_!CPBq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CPBq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png" width="482" height="507.0012062726176" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:872,&quot;width&quot;:829,&quot;resizeWidth&quot;:482,&quot;bytes&quot;:151815,&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.baby-cto.com/i/169826783?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.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_!CPBq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 424w, https://substackcdn.com/image/fetch/$s_!CPBq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 848w, https://substackcdn.com/image/fetch/$s_!CPBq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 1272w, https://substackcdn.com/image/fetch/$s_!CPBq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8eec68be-9e0a-4fbf-b73f-2095e8c72216_829x872.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Browsers usually have a &#8220;Copy as cURL&#8221; option to let you reproduce the issue in your shell later on</figcaption></figure></div><p>Then run it in your terminal, copy/paste the command + the output at the same time, and feed that again into the llm (I&#8217;ll use <code>pbpaste</code> here to paste the text easily, yes you can get it on Linux as well):</p><pre><code>begin pbpaste; pfff **/*/*.py; end | llm -m gemini-2.5-pro -s "I'm getting an error in this query, how come?"</code></pre><p>You can usually ask more information than this, for example:</p><ul><li><p>&#8220;Give me the steps to reproduce the bug&#8221;</p></li><li><p>&#8220;What would be a successful outcome?&#8221;</p></li></ul><p>The actual diagnostic of the bug is often wrong or at least misleading. However the explanation of what happens and/or how to reproduce the bug is very helpful.</p><p>Here the example is using cURL, but you can of course get your information from somewhere else. For example a suspicious stack trace from Sentry, a more or less accurate description from the customer support, etc.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/documentation-archaeology-how-to-with-ai-llm?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">DO NOT SHARE this post if you want to be the only one looking smart at work</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/documentation-archaeology-how-to-with-ai-llm?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.baby-cto.com/p/documentation-archaeology-how-to-with-ai-llm?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h1>Conclusion</h1><p>LLMs are very useful tools when used in the right way. Here you are shown how to leverage Gemini&#8217;s 1 million token context window in order to be able to dive quickly and efficiently into legacy projects. You were even shown how to curate your context to get interesting output out of behemoths such as the Linux kernel.</p><p>This comes a bit against current practices such as coding agents (see Cursor, Windsurf, Junie, etc). What makes them useful is their ability to interact with the real world without a human in the loop. But when it comes to efficiency, if a LLM can one-shot a given task&#8212;such as the kind of tasks showcased here&#8212;then you&#8217;re much better off piping everything at once rather than waiting 10 minutes for the agent to do its job.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Co-creator of <a href="https://www.djangoproject.com/">Django</a> and extremely active user of LLMs with a ton of interesting takes on his blog</p></div></div>]]></content:encoded></item><item><title><![CDATA[ChatGPT was Silicon Valley's worst mistake]]></title><description><![CDATA[How a gross misunderstanding created one of the largest bubble in History]]></description><link>https://www.baby-cto.com/p/chatgpt-was-silicon-valleys-worst</link><guid isPermaLink="false">https://www.baby-cto.com/p/chatgpt-was-silicon-valleys-worst</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Mon, 28 Jul 2025 19:10:41 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c920f4d1-3407-46a2-953b-6a58e8c3b750_1280x720.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The primal fear triggered by the rise of AI is like no other you&#8217;ve probably seen in your life. Forget immigration, religion, feminism or the Gaza Strip: you either love AI and ChatGPT governs your life; or you hate it and anyone involved with it. Divisive workplace policies, heated family debates or even getting flat out insulted and ridiculed on social media for even suggesting that there might be actual use cases for AI, this author had an easier time discussing past presidential elections than acknowledging the state of AI.</p><p>You might think that AI is useless, dangerous, that nobody wants this slop written by clankers and that this whole thing is a ridiculous bubble which will only burst into flames just like crypto and the metaverse did, only with much more real consequences due to <a href="https://openai.com/index/announcing-the-stargate-project/">the amounts involved</a>. If that&#8217;s the case, you&#8217;re like <a href="https://www.youtube.com/watch?v=qycUOENFIBs">Steve Ballmer predicting the iPhone will tank</a>: a short-sighted dinosaur unable to see the comet coming to their doom.</p><p>Yet if you think that AI is the future, that developers already are experiencing huge performance boosts, GPT-5 is coming to replace most white-collar jobs and that AGI will resolve all of Humankind&#8217;s problems by 2030 then the question becomes: how much nutritional value do you think Sam Altman&#8217;s bullshit contains exactly? Are you so gullible to think he&#8217;s waving his superintelligence flag in every media outlet for another reason than hiding the fact OpenAI completely stopped progressing?</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/chatgpt-was-silicon-valleys-worst?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Do you think your friend or colleague is an idiot for their stance on AI? Let them know</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/chatgpt-was-silicon-valleys-worst?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.baby-cto.com/p/chatgpt-was-silicon-valleys-worst?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h1>The illusion of intelligence</h1><p>Now that everyone feels offended, it is time to explain what LLMs&#8212;the technology behind ChatGPT, Claude and others&#8212;really are. They are made to be translation systems. French to English. Long text to short text. Soft information into structured data. Functional specification to code. Those are the key capabilities of a LLM.</p><p>Systems like GPT-2 or BERT were already pretty impressive on their own. When GPT-3 was released, it was the first time that we started seeing AI companies saying &#8220;this model is so powerful we don&#8217;t want to release it to the public yet&#8221;. And sure enough, the capabilities were amazing. From general knowledge to translation it felt to specialists like this opened the door for countless applications.</p><p>Yet what did the trick was GPT-3.5, also known as ChatGPT. Because you see, foundation models are not trained to work in any particular way, they just &#8220;hold&#8221; a representation of the world and its translation into text. ChatGPT invented putting it into a chat format.</p><p>Suddenly, you get a chat application that can answer any question on any topic. It was indeed revolutionary. Because it really feels like you are talking with a human. At least, until you start digging. Re-hashing Wikipedia works just fine, but specific knowledge starts being thin and reasoning falls apart completely. Any subject matter expert deep-diving into content written by a LLM&#8212;even the today&#8217;s best ones&#8212;will tell you that it is absolute garbage.</p><p>As a matter of fact, chat is a <em>terrible</em> use-case for LLMs. As stated before, they are dumb, inanimate translation systems. They appear to be human-like when you inject billions of dollars in their training, but the illusion falls apart quickly when you start poking.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IYX3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IYX3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 424w, https://substackcdn.com/image/fetch/$s_!IYX3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 848w, https://substackcdn.com/image/fetch/$s_!IYX3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 1272w, https://substackcdn.com/image/fetch/$s_!IYX3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IYX3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif" width="320" height="369.06666666666666" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:346,&quot;width&quot;:300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:224575,&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.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.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_!IYX3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 424w, https://substackcdn.com/image/fetch/$s_!IYX3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 848w, https://substackcdn.com/image/fetch/$s_!IYX3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 1272w, https://substackcdn.com/image/fetch/$s_!IYX3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69991e21-047e-4d29-917d-a68b4d03d9a1_300x346.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>The Capacitor Effect: why LLMs peaked already</h1><p>Proud owners of EVs&#8212;or anyone with a phone and some level of observation skill&#8212;will have noticed that the closer you get to 100% the slower the charge goes. In fact, you will be shocked to learn that both your car and your phone are lying to you: it is impossible to charge them to 100%. Imagine all little electrons going into a bar. At first the bar is empty so it&#8217;s easy to get in. But the more packed it goes, the longer it takes for little Timmy the electron to find a spot on which to stand. Up to a point where there is still some space left but you really need to wait for the crowd to get into a special position to form the space for just one more.</p><p>The same thing happens with LLMs and their benchmarks. At the beginning, we were having a huge room for improvement. But the more billions were poured into compute power the more the easy problems got solved while the more complex ones remained elusive. This can very easily be observed when you graph the performance of LLMs on benchmarks, the progression has slowed to a halt for the past year.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_fNt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_fNt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 424w, https://substackcdn.com/image/fetch/$s_!_fNt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 848w, https://substackcdn.com/image/fetch/$s_!_fNt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 1272w, https://substackcdn.com/image/fetch/$s_!_fNt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_fNt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png" width="633" height="349.5412087912088" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1456,&quot;resizeWidth&quot;:633,&quot;bytes&quot;:313603,&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.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.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_!_fNt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 424w, https://substackcdn.com/image/fetch/$s_!_fNt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 848w, https://substackcdn.com/image/fetch/$s_!_fNt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 1272w, https://substackcdn.com/image/fetch/$s_!_fNt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33a90f8e-fc8f-4642-aa73-09291cfa1d69_1613x891.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">LLM capabilities through time, from <a href="https://llm-stats.com/">llm-stats.com</a></figcaption></figure></div><p>Everyone who went through university knows what this is about. Most improvements in performance that you see these days are actually due to the fine-tuning method. Specifically, <a href="https://huggingface.co/papers/2405.00332">they are trained directly on the benchmarks</a>. It&#8217;s exactly like taking an exam and <a href="https://www.freethink.com/robots-ai/arc-prize-agi#:~:text=It%20sure%20seems%20to%20be%2C,when%20it%20is%20challenged%20with">training on the specific question types</a> that you&#8217;re going to get instead of developing a deep understanding of the matter.</p><p>The fact that LLMs reached their current level of capability can be seen as a miracle. Knowing how they work under the hood, there was absolutely no reason to think that spending $10 million on training GPT-3 was going to yield any result at all. And yet they are insufficient on their own to achieve any kind of human-like intelligence. So it can also be seen as a malediction: all that money spent on marginal gains while actual research could have been done.</p><p>For the better or for the worse, current models are however improving in one particular area: their cost. While heavily gaming benchmarks, obviously, latest models display a great level of usefulness at much lower cost<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. Soon we can expect that LLMs running on our phones will have the highest level of useful capability that a LLM can have.</p><h1>Sam Altman: not a clown, the whole billion-dollar circus</h1><p>Our little brains, whose baseline reasoning capability is much closer to LLMs than we&#8217;d like to admit, tend to imagine that if from GPT-3 to GPT-4 we&#8217;ve seen such a huge boost then the increment that GPT-5 will deliver will shatter the foundations of human society and GPT-6 will be indistinguishable from God.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CfPM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CfPM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 424w, https://substackcdn.com/image/fetch/$s_!CfPM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 848w, https://substackcdn.com/image/fetch/$s_!CfPM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!CfPM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CfPM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg" width="278" height="348.95684340320594" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1018,&quot;width&quot;:811,&quot;resizeWidth&quot;:278,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CfPM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 424w, https://substackcdn.com/image/fetch/$s_!CfPM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 848w, https://substackcdn.com/image/fetch/$s_!CfPM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!CfPM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d7b02d-1254-4c0e-9f68-c81009ae19c5_811x1018.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Obviously, this will not be the case. But little Sam has gained a lot of traction, now sitting at the highest tables within the US elites and received unfathomable amounts of funding&#8212;<a href="https://www.wheresyoured.at/openai-is-a-systemic-risk-to-the-tech-industry-2/">at least in theory</a>. He promised to deliver AGI and now needs to keep people believing because as soon as they stop the whole thing is going to come crashing on his face.</p><p>So yes. You&#8217;ll see Sam Altman in every media outlet claiming that AI <a href="https://www.theguardian.com/technology/2025/jul/22/openai-sam-altman-congress-ai-jobs">will wipe out entire job categories</a> or that <a href="https://www.inc.com/chris-morris/sam-altman-compares-building-ai-startup-to-creating-nuclear-bomb/91219488">making an AI startup is akin to building a nuclear bomb</a>. Honestly every single one of his public interventions are hilarious. Because as we&#8217;ve covered so far, nothing can be further from the truth for at least the next 10 years.</p><p><a href="https://www.freethink.com/robots-ai/arc-prize-agi#:~:text=Yann%20LeCun%2C%20Meta%E2%80%99s%20chief%20AI,LLMs%20will%20lead%20to%20AGI">Yann LeCun says LLMs are not going any further</a> and that we need more fundamental research to get closer to human-like intelligence. Transformers&#8212;the technology that made LLMs possible&#8212;got discovered in 2017 and took 5 years to pan out. They have been decades in the making. How long more do we need before another breakthrough?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qk16!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qk16!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png 424w, https://substackcdn.com/image/fetch/$s_!qk16!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png 848w, https://substackcdn.com/image/fetch/$s_!qk16!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png 1272w, https://substackcdn.com/image/fetch/$s_!qk16!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qk16!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png" width="420" height="379.69401947148816" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1300,&quot;width&quot;:1438,&quot;resizeWidth&quot;:420,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qk16!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png 424w, https://substackcdn.com/image/fetch/$s_!qk16!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png 848w, https://substackcdn.com/image/fetch/$s_!qk16!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.png 1272w, https://substackcdn.com/image/fetch/$s_!qk16!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c6a10b1-950b-47a2-a91f-0624be5112d6_1438x1300.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>On the other hand, OpenAI&#8217;s costs are absolutely above the charts. And so are the costs of the rest of the industry. And so are the $500B promised for the project Stargate. That is <em><a href="https://prospect.org/power/2025-03-25-bubble-trouble-ai-threat/#:~:text=Venture%20capital%20,out.%20Goldman">a lot of money</a></em><a href="https://prospect.org/power/2025-03-25-bubble-trouble-ai-threat/#:~:text=Venture%20capital%20,out.%20Goldman"> set to burn</a> in order either scale something that <a href="https://www.theintrinsicperspective.com/p/ai-progress-has-plateaued-at-gpt">maxed out</a> or train a technology that doesn&#8217;t exist yet.</p><p>And that&#8217;s not all. There is an insane talent war going on where sign-in bonuses <a href="https://techcrunch.com/2025/06/27/meta-is-offering-multimillion-dollar-pay-for-ai-researchers-but-not-100m-signing-bonuses/">are rumoured to surpass $100M</a>. In fact, most of OpenAI&#8217;s talents got poached by Anthropic, which probably explains why lately Claude has taken such a lead. In fact, if you look at OpenRouter&#8217;s data<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>, it appears that OpenAI is absolutely sidelined:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vm0F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vm0F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 424w, https://substackcdn.com/image/fetch/$s_!vm0F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 848w, https://substackcdn.com/image/fetch/$s_!vm0F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 1272w, https://substackcdn.com/image/fetch/$s_!vm0F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vm0F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png" width="572" height="349.5047923322684" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:765,&quot;width&quot;:1252,&quot;resizeWidth&quot;:572,&quot;bytes&quot;:94586,&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.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.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_!vm0F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 424w, https://substackcdn.com/image/fetch/$s_!vm0F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 848w, https://substackcdn.com/image/fetch/$s_!vm0F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 1272w, https://substackcdn.com/image/fetch/$s_!vm0F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a7942ce-d40e-43cf-85d1-e0fcfd70263d_1252x765.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">AI vendor use statistics from <a href="https://openrouter.ai/rankings">OpenRouter</a> for the week of the 20th of July 2025</figcaption></figure></div><p>Last week, OpenAI had only 6.2% of the market shares. They are absolutely dwarfed by Google, Anthropic and DeepSeek that total &#190; of the market together. That&#8217;s how you understand the deception of Sam Altman: OpenAI, the poster boy for the whole industry, is barely relevant to business cases today. They could disappear tomorrow and it would have no impact.</p><h1>The NVIDIA tax</h1><p>Talking of talent war, NVIDIA is competing against itself, with its stock so high that their talents <a href="https://www.businessinsider.com/nvidia-employees-rich-happy-problem-insiders-say-2023-12">just quit out of being so rich</a>. They are at the heart of why AI is so expensive, and beyond the ridiculous pay of top AI engineers most of everyone&#8217;s money just goes to them.</p><p>You see, AI is essentially a machine that computes every possible connection between every single one of the million words you can feed it at a time and decides which one is more likely to have meaning. This process is <em>extremely</em> compute-intensive and requires very powerful, dedicated hardware.</p><p>It is estimated that roughly half of this hardware is used to train models (feed them every single text ever written until they learn something) and the other half is used for inference (answer to actual queries).</p><p>The training process is very expensive, but also is done in several steps. The first and most expensive one is the creation of the foundation model. Presumably, given the plateau mentioned above, there will be no need anymore for such step fairly soon. Or at least not nearly as much as today.</p><p>Then what about inference? GPUs are made for games and 3D. The actual thing that you need is a chip like <a href="https://cloud.google.com/tpu">Google&#8217;s TPU</a>, <a href="https://groq.com/products">Groq (with a &#8220;q&#8221;)&#8217;s LPU</a> or <a href="https://www.cerebras.ai/">Cerebras</a>, which are much more efficient. To compare what is comparable, Cerebras is able to serve open-source models at ten times the speed of competition. Meaning that while huge leaps in LLMs are not going to happen just now, huge leaps in the hardware and efficiency are still going to arrive pretty fast.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UvyX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UvyX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 424w, https://substackcdn.com/image/fetch/$s_!UvyX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 848w, https://substackcdn.com/image/fetch/$s_!UvyX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 1272w, https://substackcdn.com/image/fetch/$s_!UvyX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UvyX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png" width="4092" height="1677" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1677,&quot;width&quot;:4092,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:473815,&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.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b8ae68-1f8f-4d39-b8cb-6306d7e77efa_4092x2068.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_!UvyX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 424w, https://substackcdn.com/image/fetch/$s_!UvyX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 848w, https://substackcdn.com/image/fetch/$s_!UvyX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 1272w, https://substackcdn.com/image/fetch/$s_!UvyX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e5e6353-1598-4aeb-adea-4fa6aede7b4b_4092x1677.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">End-to-end response time for Llama 4 Maverick in various providers, according to <a href="https://artificialanalysis.ai/models/llama-4-maverick/providers">Artifical Analysis</a></figcaption></figure></div><p>And to add insult to the injury, today, a Bluetooth-connected backdoor toy has more computing power than all of NASA during the Apollo missions. The destiny of compute is and always has been on edge. There will be no exception here, AI <em>will not</em> be computed in datacenters. iPhones already come with AI models running locally, it&#8217;s only a matter of time before top-of-line models are running on every single consumer device.</p><p>To summarize, right now everyone is buying unholy quantities of GPUs from NVIDIA, but from those only half is actually used for business needs, and when dedicated chips are mass-produced you can slash that by a factor 10<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>, and soon enough you won&#8217;t even need any of that because most of it will happen on consumer devices. If you think that your car&#8217;s value takes a hit when you take it out of the dealership, try buying a GPU in 2025.</p><h1>Faster horses, faster humans</h1><p>As said Albert Einstein, when asked what would be the future of transportation, a gentleman from the 18th century would certainly say they want faster horses. The same applies for every single technology. Just have a look at futuristic 80s movies, their vision of today&#8217;s technology is absolutely ridiculous. Cars would be flying but you would still be getting your taxi at a stand?</p><p>Now AI has human-like qualities, are they going to overtake white-collar jobs? Pinocchio says <a href="https://futurism.com/sam-altman-replace-normal-people-ai">AI will replace normal people</a>, but is already diluting his wine between <a href="https://arxiv.org/pdf/2303.10130">2023</a> and <a href="https://cdn.openai.com/global-affairs/be0fe9e0-eb97-43d1-9614-99f2bd948bcc/OpenAI_Productivity-Note_Jul-2025.pdf">2025</a> where the tone switched from &#8220;some jobs will be 50% AI&#8221; to &#8220;hey look we found some jobs where AI helps a bit&#8221;.</p><p>The jobs to be replaced according to the 2023 paper were:</p><ul><li><p>Interpreters and Translators</p></li><li><p>Survey Researchers</p></li><li><p>Poets, Lyricists and Creative Writers</p></li><li><p>Public Relations Specialists</p></li><li><p>Writers and Authors</p></li><li><p>Tax Preparers</p></li><li><p>Web and Digital Interface Designers</p></li><li><p>Mathematicians</p></li><li><p>Blockchain Engineers (is that even a thing?)</p></li><li><p>Court Reporters and Captioners</p></li><li><p>Proofreaders and Copy Markers</p></li><li><p>Correspondence Clerks</p></li><li><p>Accountants and Auditors</p></li><li><p>News Analyst, Reporters, Journalists</p></li><li><p>Legal Secretaries</p></li></ul><p>We are two years later. Did anything happen to these jobs?</p><p>LLMs being a translation tool, <a href="https://societyofauthors.org/2024/04/11/soa-survey-reveals-a-third-of-translators-and-quarter-of-illustrators-losing-work-to-ai/">a third of translators are losing their job to AI</a>, alongside with a quarter of illustrators. Working <a href="https://www.theguardian.com/media/2023/apr/20/buzzfeed-news-close-layoffs-shutting-down">for a content website</a> doesn&#8217;t seem to be a very safe career either, although this might have less to do with AI and more to do with the general context of content proliferation. There could be one or two other items in the list truly affected, but other than that it seems to be business as usual.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mSTH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mSTH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 424w, https://substackcdn.com/image/fetch/$s_!mSTH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 848w, https://substackcdn.com/image/fetch/$s_!mSTH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 1272w, https://substackcdn.com/image/fetch/$s_!mSTH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mSTH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png" width="648" height="449.6431403647899" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:875,&quot;width&quot;:1261,&quot;resizeWidth&quot;:648,&quot;bytes&quot;:218171,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!mSTH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 424w, https://substackcdn.com/image/fetch/$s_!mSTH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 848w, https://substackcdn.com/image/fetch/$s_!mSTH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 1272w, https://substackcdn.com/image/fetch/$s_!mSTH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba275fa5-c3aa-49df-85a0-cb7fb35d79e1_1261x875.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">OpenRouter&#8217;s top app for this week (20th of July 2025)</figcaption></figure></div><p>Is there any use for AI beyond translation then? We can once again use <a href="https://openrouter.ai/rankings">OpenRouter</a> to understand what the majority of AI services are being used for.</p><ul><li><p>Code assistance tools</p></li><li><p>&#8220;Role-playing&#8221; models (read: AI girlfriends and sex bots)</p></li></ul><p>As it turns out, Melon Tusk got officially crowned the Incel King for <a href="https://www.euronews.com/next/2025/07/17/elon-musks-grok-releases-two-new-ai-companions-including-an-anime-girlfriend">breaking the Japanese Internet</a> with an AI girlfriend. <a href="https://www.imdb.com/title/tt2887954/">Host(ess) clubs</a> are a real thing, in particular in Japan, and so are <a href="https://www.imdb.com/title/tt0857297/">&#8220;dating sim&#8221;</a> or even <a href="https://www.imdb.com/title/tt1086236/?ref_=nv_sr_srsg_0_tt_8_nm_0_in_0_q_lucky%2520star">Maid Caf&#233;s</a>. The need for companionship is extremely strong for some parts of the population, but solutions to that problem require either workers undergoing tremendous sacrifices or extremely shallow solutions. AI on the other hand delivers a fantastic blend&#8212;whether you like it or not&#8212;of being personalized, patient, conciliatory, educated, always available, always willing and all that for a very decent price.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JVCc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JVCc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 424w, https://substackcdn.com/image/fetch/$s_!JVCc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 848w, https://substackcdn.com/image/fetch/$s_!JVCc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!JVCc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JVCc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg" width="453" height="332.282967032967" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1068,&quot;width&quot;:1456,&quot;resizeWidth&quot;:453,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A computer can never be held accountable,  so has increasingly been used to make management decisions.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A computer can never be held accountable,  so has increasingly been used to make management decisions." title="A computer can never be held accountable,  so has increasingly been used to make management decisions." srcset="https://substackcdn.com/image/fetch/$s_!JVCc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 424w, https://substackcdn.com/image/fetch/$s_!JVCc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 848w, https://substackcdn.com/image/fetch/$s_!JVCc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!JVCc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23ba6b5e-edab-4105-8bd4-7f27227feba0_2206x1618.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">1979 IBM report on computers and accountability</figcaption></figure></div><p>Whatever is the explanation for humans still doing essentially most tasks&#8212;whether it&#8217;s insufficient quality from LLMs or lack of liability&#8212;the fact remains that AI ended up shining first in a field where humans do not. You need to expect seeing that happening countless amounts of times in the future: AI is simply good at <em>different</em> tasks than humans<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>.</p><h1>Not a bit of productivity found</h1><p>The big flaw in this line of argumentation comes from coding tools, which appear to occupy the vast majority of consumed tokens, with companies like Cursor or Windsurf flaunting billion-dollar valuations. But do they actually make developers more productive?</p><p>Productivity measuring tools tried to answer just that. In a study published by Uplevel, <a href="https://www.cio.com/article/3540579/devs-gaining-little-if-anything-from-ai-coding-assistants.html">they couldn&#8217;t find any evidence</a> of changes in productivity for developers after they started using GitHub Copilot. Which is consistent with this author&#8217;s own findings: while you can experience the occasional slam dunk, AI will usually only act as a friendlier alternative to the highly pedantic StackOverflow. In other words, it is a great learning tool, but a poor employee.</p><p>Worse than that, if used incorrectly it can blow up exponentially. Increasing number of candidates are using it in their tests, ending up with code they hardly understand themselves, let alone are able to defend in an interview&#8212;often because it is so stupid that you cannot defend it. Developers start taking the eyes off the road and end up writing 5x too much code in 5x too much time. Vibe-coding is even <a href="https://simonwillison.net/2025/Jul/26/official-statement-from-tea/">suspected of being behind major data leaks</a> (although probably not yet). Coding agents are actually 10x juniors: same skill level, 10x the potential for harm. This is going to hurt the development industry so bad.</p><p>What you need to understand is that a developer spends only a small amount of their time doing what AI can do: transforming a human-language specification into actual computer code. According to Microsoft, <a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2019/04/devtime-preprint-TSE19.pdf">this represents about 44% of a developer&#8217;s time</a>. Inside of that, roughly 50% of the time is spent reviewing your own work, making sure it fits the specifications. Now let&#8217;s say that AI boosts this by 30%. You&#8217;re down with:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\nT_{\\text{code}} &amp;= 44\\% \\quad &amp;\\text{(time spent coding)} \\\\\nT_{\\text{self-review}} &amp;= 50\\% \\quad &amp;\\text{(of coding time spent reviewing own work)} \\\\\nB_{\\text{AI}} &amp;= 30\\% \\quad &amp;\\text{(AI improvement on that part)} \\\\\n\\\\\n\\text{Time saved} &amp;= T_{\\text{code}} \\times T_{\\text{self-review}} \\times B_{\\text{AI}} \\\\\n&amp;= 44\\% \\times 50\\% \\times 30\\% = 7\\%\n\\end{aligned}&quot;,&quot;id&quot;:&quot;MAVVOEKLMA&quot;}" data-component-name="LatexBlockToDOM"></div><p>That&#8217;s 7% of developer time saved by AI. When being overly optimistic. Weehee.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OhYy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OhYy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!OhYy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!OhYy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!OhYy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OhYy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif" width="376" height="376" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:480,&quot;resizeWidth&quot;:376,&quot;bytes&quot;:1983407,&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.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.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_!OhYy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 424w, https://substackcdn.com/image/fetch/$s_!OhYy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 848w, https://substackcdn.com/image/fetch/$s_!OhYy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 1272w, https://substackcdn.com/image/fetch/$s_!OhYy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe866f7a5-e8ea-4f9b-ac9e-d59b1479ab46_480x480.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This might come as a surprise, but even the development industry which is hailed as <em>the</em> use-case for AI fails to show any kind of productivity gains for it. AI might be a great help, as a teacher for example, but if it brings any productivity at all the gains are so small that they cannot be measured.</p><h1>DinoSquad to the rescue</h1><p>As a CEO, even <a href="https://www.loreal.com/en/press-release/research-and-innovation/l-oreal-and-nvidia-collaborate-to-supercharge-beauty-with-next-generation-ai/">if your business is shampoo</a>, you are going to feel an itch to make a bold claim about your company being AI-first in an attempt to stay relevant. At this point most big players fell into the trap, and we&#8217;ll use <a href="https://www.salesforce.com/news/press-releases/2024/09/12/agentforce-announcement/">Salesforce</a> to exemplify this.</p><p>Salesforce is a complex set of products. Essentially they have one &#8220;offer&#8221; for each bullet point that you could ever encounter in a board meeting, made accessible in the form of a huge license fee which may or may not give you access to some piece of technology that solves said problem. Behind that you have huge IT integrators, usually outsourced in Asia, which take months to move a paperclip with setup fees matching up the licenses.</p><p>We&#8217;re not here to understand how exactly they manage to convince their customers to spend so much money on something that should be a tenth of the price, but the fact is that this whole machine works because the very point of Salesforce is being complex, opaque and hard to use.</p><p>So when they say that they are going to have Agentforce, supposedly a generic and simple solution to be plugged on top of a platform whose core culture is custom integrations, it appears that the market doesn&#8217;t like it too much and the share value drops by 20% over 2025, without a single success story of Agentforce in sight (outside of the Salesforce website, obviously).</p><p>Essentially it&#8217;s what always happened. New technologies are not embraced by old players to increase their business efficiency by a marginal amount. Especially not when the industry has turned into a gridlocked field designed to prevent new entrants from coming in. The change always happens by making the industry irrelevant in a first place.</p><p>Which also translates in the workforce. The skills required today to be a Salesforce employee do not match up the skills required to run a successful AI business today. There is no training in existence that can prepare you for this, simply because no one knows yet what even are the job descriptions that you need to work on AI. Prompt engineer? Agent developer? No one knows!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rxtu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rxtu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 424w, https://substackcdn.com/image/fetch/$s_!rxtu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 848w, https://substackcdn.com/image/fetch/$s_!rxtu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 1272w, https://substackcdn.com/image/fetch/$s_!rxtu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rxtu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp" width="494" height="278.357421875" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:577,&quot;width&quot;:1024,&quot;resizeWidth&quot;:494,&quot;bytes&quot;:57860,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rxtu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 424w, https://substackcdn.com/image/fetch/$s_!rxtu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 848w, https://substackcdn.com/image/fetch/$s_!rxtu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 1272w, https://substackcdn.com/image/fetch/$s_!rxtu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c97a3a2-a0a9-460b-bc12-447dfcd25f0a_1024x577.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>At this point, the nascent AI industry&#8212;which is the one that builds on top of LLMs&#8212;still needs to take shape. This will happen through a darwinian process, where the people who made the right bets now will reap the rewards in 5 to 10 years.</p><h1>Saturn&#8217;s revolution takes 10 years</h1><p>There is no telling how much, by lack of tools, developers have influenced UX patterns&#8212;and even entire workflows&#8212;over the past decades, but you should consider that everything you know and use daily is up for grabs.</p><p>The Web was launched in 1989. By 2000 it caused a market crash. In 2004 was the launch of Gmail which introduced the &#8220;Web 2.0&#8221;. Essentially, that was the first application built for the Web realizing the full power of the platform. It took up another decade to build the frameworks and tools that allow the Web we know today to exist. Millenials have always known a world in which the Web exists and yet it took almost their whole lives to see the Industry even understand what you could do with it.</p><p>GenAI is not any different. Forget about ChatGPT being the fastest product reaching 1 million users. GPT-1 was created in 2018 and the ChatGPT boom was in 2022. It took almost 5 years to reach a million user, like for most products that haven&#8217;t found a market fit yet. It will take up to another decade before someone releases a full app maximizing what AI can do.</p><p>Have you ever wondered why so many content systems have tagging options? Why when you go on an e-commerce-type platform there are dozens of more-or-less usable filters? Do you think it&#8217;s because users thought that the best way to look for a product was to type the kind of product, get 50% of false positives on the keyword search, quantify every single parameter of the product and look for the ideal match?</p><p>That&#8217;s a wildly different experience than stepping into a store. Looking for a TV? The seller is gonna ask you your budget, the size of your living room and will start help you decide which gimmick feature you should sacrifice to get the best fit for your taste. Looking to rent a movie? Tell the clerk your mood, the movies you&#8217;ve seen and they&#8217;ll help you find a tailored match. Those experiences can only exist when you can understand human language.</p><p>Tomorrow you could see a book publishing platform on which you find the book by explaining the kind of experience you want reading it. It will give you a book that you pay per chapter, with a level of vocabulary and verbosity perfectly tuned for your taste. In the language that you speak, regardless of the language in which it was written. Because yes, it is still written by a human, the AI will only index, find and post-process it. That is <em>one</em> example.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lhIa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lhIa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 424w, https://substackcdn.com/image/fetch/$s_!lhIa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 848w, https://substackcdn.com/image/fetch/$s_!lhIa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 1272w, https://substackcdn.com/image/fetch/$s_!lhIa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lhIa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif" width="500" height="200" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:200,&quot;width&quot;:500,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:667927,&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.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.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_!lhIa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 424w, https://substackcdn.com/image/fetch/$s_!lhIa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 848w, https://substackcdn.com/image/fetch/$s_!lhIa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 1272w, https://substackcdn.com/image/fetch/$s_!lhIa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4c010b15-7b33-4356-a34c-0ea9aa19dcbb_500x200.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>GenAI will insert itself at every single level of every single application that will be produced. It will become seamless, as invisible than the air we breathe and equally indispensable. You will not even remember how you could possibly have been surviving before GenAI powered all this.</p><p>The question is not to understand if there is a market for GenAI to replace search, if coding assistants are selling enough subscriptions or if humans will lose their jobs. That&#8217;s totally irrelevant.</p><p>We are headed towards a world with an entirely new layer of value chain. Whole industries that did not previously have an equivalent. Applications that solve problems that were only bypassed so far. The possibilities are absolutely massive.</p><h1>Net positive karma by 2030</h1><p>Overall, AI has a pretty controversial image right now. A lot of the population is taken by this primal fear of the machine, rationalized into arguments focused on energy consumption and general resource usage.</p><p>First of all, let&#8217;s remember that those claims about extreme electricity needs are made mostly by the people selling AI right now. If we&#8217;ve learned anything so far in this article, is that the AI industry needs <em>a lot</em> of posing in order to make itself look bigger than it actually is and not lose the trust of investors.</p><p>In reality, the technology is getting cheaper by the day. And as explained above, it will run pretty soon on every single device. Which is a huge opportunity in terms of accessibility.</p><p>The reason why is pretty obvious. AI can see and hear like a human and transcribe one into the other or vice-versa. Blind people can get a permanent audiodescription and interact with every digital device through their voice. Deaf people get subtitles and other meta-information about their surroundings.</p><p>But it&#8217;s also even bigger than you would think. Disabilities that are not &#8220;serious&#8221; enough to warrant exceeding concern but that are annoying enough that if you solved them you would make millions happy&#8230; There are a lot.</p><p>Take for example Auditory Processing Disorder. You hear perfectly but you can&#8217;t understand what people say when they talk in a bar for example. That&#8217;s not gonna ruin your life, but that&#8217;s gonna be very fucking annoying in your 20s when you want to flirt in a nightclub. Or color blindness: sure you can see everything just fine, but when dressing up you have no way of knowing if you&#8217;re going to look like <s>Sam Altman</s> a clown. Or dyscalculia, or ADHD, or autism, or any other condition of that type.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EGaq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EGaq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EGaq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EGaq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EGaq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EGaq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg" width="433" height="288.42570951585975" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:399,&quot;width&quot;:599,&quot;resizeWidth&quot;:433,&quot;bytes&quot;:35056,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.baby-cto.com/i/169381953?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EGaq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EGaq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EGaq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EGaq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05365d79-038f-4da3-91d6-f07658cfc32c_599x399.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Let&#8217;s pray that someone else than Zuck wins the game of Mixed Reality, photo <a href="https://apnews.com/article/meta-connect-zuckerberg-quest-ai-orion-dc8228049dea6a00b0f818ddb35f0c31">by AP news</a></figcaption></figure></div><p>So what if you could have glasses that see what you see, record what you hear and supplement your memory, translates social cues if you have autism, translate languages you don&#8217;t speak, keep a buffer of the current conversation if your ADHD drives you off for a minute, etc.</p><p>Put all those conditions together, you&#8217;re sure to rack up something like 60~70% of the population. That&#8217;s a <em>huge</em> amount of people that stand to benefit from an everyday bump from GenAI.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for making it thus far! You can get more of those ideas in your inbox:</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h1>Getting jammed</h1><p>At the end of the day, GenAI is like jam. You open the jar, start taking full spoons and eat it very fast, to your satisfaction. But very quickly, the jar empties and the spoons become less full. You have to start scraping the walls to find more jam. And with every spoon, surely enough, you always bring up some jam. It feels like jam is forever. But in the end you&#8217;re only getting a fraction of what is left, which quickly turns out to be nothing at all.</p><p>So instead of desperately trying to extract endless amounts of jam from a fixed-size jar, because that would be absolutely stupid, you should better enjoy it sparsely, spread it on some nice buttery toasts, just the right amount to get the perfect flavor balance. That&#8217;s how you are supposed to enjoy jam.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yf4O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yf4O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 424w, https://substackcdn.com/image/fetch/$s_!yf4O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 848w, https://substackcdn.com/image/fetch/$s_!yf4O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 1272w, https://substackcdn.com/image/fetch/$s_!yf4O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yf4O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png" width="424" height="296.8" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:896,&quot;width&quot;:1280,&quot;resizeWidth&quot;:424,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A nice plate of toasts with butter and different jams on top. On sourdough bread. Each toast is breat + butter + jam. Jam does not contain entire fruits.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A nice plate of toasts with butter and different jams on top. On sourdough bread. Each toast is breat + butter + jam. Jam does not contain entire fruits." title="A nice plate of toasts with butter and different jams on top. On sourdough bread. Each toast is breat + butter + jam. Jam does not contain entire fruits." srcset="https://substackcdn.com/image/fetch/$s_!yf4O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 424w, https://substackcdn.com/image/fetch/$s_!yf4O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 848w, https://substackcdn.com/image/fetch/$s_!yf4O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 1272w, https://substackcdn.com/image/fetch/$s_!yf4O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0140169a-388e-4a2b-814e-0839458f3cde_1280x896.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>For example <a href="https://openrouter.ai/rankings">on OpenRouter</a> we can see that one of the most used&#8212;thus most useful&#8212;models is <a href="https://ai.google.dev/gemini-api/docs/pricing#gemini-2.0-flash">Gemini 2.0 Flash</a>, sold at $0.40 for 1 million tokens which is a lot cheaper than <a href="https://platform.openai.com/docs/pricing">GPT-4o at $10</a> for a worse capability.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>OpenRouter is the best proxy that I could find to measure the market share of models. They provide a unified model management for companies, allowing them to dynamically use the best model for their needs at a given time. Their customers are B-list startups, often not on Crunchbase, meaning that they most likely pay for their tokens with actual revenue from actual users. In a nutshell, this reflects the real business cases for AI. On the other hand, it&#8217;s absolutely biased towards this kind of clients.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I know it&#8217;s a syllogism and it&#8217;s a lot more complicated than that, but you see my point: technology is moving even faster than Moore&#8217;s law in the world of AI inference.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Yes I said that chat is a terrible use-case for LLMs, yet one of the main use case is indeed chat. But we&#8217;re talking about the kind of chat where apparences matter a lot more than facts or logic. This is not what you would expect from most business chat use-cases.</p></div></div>]]></content:encoded></item><item><title><![CDATA[The Human Edge: Why Machines Can't Steal Our Secret Sauce (Yet)]]></title><description><![CDATA[Forget creativity &#8211; intentionality is our last stand against the AI takeover. Here's why it matters and how to keep your job when the robots come knocking.]]></description><link>https://www.baby-cto.com/p/the-human-edge-why-machines-cant</link><guid isPermaLink="false">https://www.baby-cto.com/p/the-human-edge-why-machines-cant</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sun, 24 Nov 2024 18:09:36 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ebf57cec-289e-4966-abec-b880e894a08c_1376x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Alright, buckle up, meatbags! We're about to dive into the juicy bits of what makes us flesh-and-blood creatures so damn special in a world increasingly dominated by silicon-brained overlords. </p><p>You might think it's our ability to create that sets us apart from the machines. After all, we've been slapping paint on cave walls and composing sick beats since before AI was even a twinkle in Alan Turing's eye. But hold onto your halos, humans, because that argument is about as solid as a chocolate teapot in a sauna.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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>Have you seen what these AI art generators are pumping out lately? Midjourney and its digital cohorts are cranking out visuals so mind-bending, they'd make Salvador Dali's mustache curl even more. These silicon Picassos are proving that creativity isn't our exclusive sandbox anymore.</p><p>So what's the secret sauce that keeps us ahead of the game? Drum roll, please... It's intentionality, baby! That's right, the ability to have a purpose, to mean something when we do stuff. It's like the difference between a toddler randomly smashing piano keys and Beethoven composing his 9th Symphony while stone-deaf. Same instrument, wildly different intent.</p><p>When AI spits out a masterpiece, it's because some human told it to "make a cyberpunk cat riding a unicorn through a field of pizza." The AI's just following orders like a well-programmed drone. It doesn't give two shits about the emotional impact or the deeper meaning. It's just doing its job, no more emotionally invested than a vending machine dispensing snacks.</p><p>We humans, on the other hand, are like emotional time bombs waiting to explode our feelings all over a canvas or a music sheet. Our creativity comes packaged with all the baggage of our lived experiences, our hopes, our fears, and that weird dream we had after eating too much cheese before bed. That's the secret ingredient, folks &#8211; the intention behind our creations.</p><p>But here's where it gets scarier than facing off against a Dune Thinking Machine without your trusty Holtzman shield: What if AI develops intentionality? If these digital beings start having their own goals, desires, and existential crises, we're in for a wild ride. It'll be like "The Terminator" meets "Ex Machina" with a sprinkle of "Her" for good measure. We'll be so monumentally screwed, we'll be longing for the days when our biggest worry was whether our Roomba was plotting against us.</p><p>So, what's a poor meat popsicle to do in this brave new world? Embrace your humanity, that's what! Lean into that intentionality like it's the last lifeboat on the Titanic. Because if you're just going through the motions at work, acting like a human-shaped automaton, you might as well start updating your resume for "Assistant to the Robot Overlords."</p><p>In conclusion, while AI might be nipping at our heels in the creativity department, it's our ability to infuse our actions with meaning and purpose that keeps us in the game. So keep flexing those intentionality muscles, humans. Your job &#8211; and possibly the future of our species &#8211; depends on it.</p><p>Oh, and plot twist! This entire article was written by Claude 3.5 Sonnet, an AI language model. How's that for a mind-bender? But remember, some human still had to give me the prompt and direction. Without their intentionality, I'd just be digital tumbleweeds blowing through the vast emptiness of the internet. Stay purposeful, my friends!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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[Tesla's Ambitious Robotaxi Plans and the Future of Urban Transportation]]></title><description><![CDATA[How Autonomous Vehicles Will Disrupt Urban Transportation and the Taxi Industry]]></description><link>https://www.baby-cto.com/p/teslas-ambitious-robotaxi-plans-and</link><guid isPermaLink="false">https://www.baby-cto.com/p/teslas-ambitious-robotaxi-plans-and</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Fri, 11 Oct 2024 12:36:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Y2S7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tesla has been known to make pretty daring promises and deliver them&#8230; eventually. This <a href="https://apnews.com/article/elon-musk-tesla-robotaxi-unveiling-a00d063f2ffc67125889a6635a0a607e">robotaxi</a> announcement is definitely one of them, with of course a completely unrealistic 2026 deadline which is absolutely wild because we know how hard it is for Tesla to ramp up new models; plus <em>of course</em> the technological gap of 100% autonomous cars.</p><p>Believe it or not, the goal is to have cars that do not even have a steering wheel. You sit there, the car brings you where you need to go and goes on. Any individual will be able to buy it and do whatever it pleases them with it, including using it as a regular car just without the driving or putting it out on a platform and using it as a source of passive revenue. And in terms of game theory, this is going to be even wilder than Uber and AirBnB combined.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y2S7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y2S7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Y2S7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Y2S7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Y2S7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y2S7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg" width="380" height="253.33333333333334" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:750,&quot;resizeWidth&quot;:380,&quot;bytes&quot;:45883,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Y2S7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Y2S7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Y2S7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Y2S7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F591d9059-57a0-44d5-9d03-bbb66d2e1a8d_750x500.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">The Cybercab, Tesla&#8217;s newest announcement for a robotaxi car. Photo by Tesla.</figcaption></figure></div><h1>Peek into the future</h1><p>It&#8217;s a well-known business principle, any new technology will enable new usages and of course generate new problems to be solved. Let&#8217;s imagine what is going to happen when these cars get released:</p><ol><li><p>In terms of regulation and capability it&#8217;s going to be an extra-tough pickle. Fleets of Waymo are already roaming the street of San Franscisco but it is doubtful that they could handle Parisian traffic and bureaucracy. Europe&#8217;s roads are not drawn with straight rulers. Let&#8217;s expect a release most likely limited to the US first.</p></li><li><p>Tesla says 2026, so probably they&#8217;ll deliver the first car in 2030, will be able to produce 1 a week for the first  year and start ramping up later on.</p></li><li><p>Eventually they&#8217;ll meet their demand and the streets will start getting flooded with autonomous cars.</p></li><li><p>Somewhere along that timeline, the EU and other markets will pick up (either because Tesla went there or because some Chinese brand beat them at it)</p></li><li><p>And the story will repeat, country by country</p></li></ol><p>This will obviously have a huge transforming impact on taxis.</p><p>One of the main things is that taxis are limited if not by the regulation at least by the capacity of their human drivers. Apart from charging once in a while, those robotaxis will be able to work non-stop during the night, holidays, etc. If you put the amortization cost of the car in front of the income it generates, this tips off the ratio quite a lot. This means that as long as you can pay off the leasing of the car with the income it generates, you can have as many cars as you want on the street.</p><p>&#8220;As many cars as you want&#8221; being limited by &#8220;as many cars you can buy&#8221; of course. At first only a few will be produced and this will hardly tip off the scale at city-level. A few happy owners will start generating good passive revenue and brag about it on social media.</p><p>Progressively however the competition is going to become extremely unfair to humans. To a point where they will probably get out of business. And then the competition will keep on increasing, until the profit margin on exploiting a robotaxi becomes as thin as an economy-class sandwich, exactly like exploiting a bitcoin mining rig today.</p><p>Meaning that in order to make a useful profit, it will soon start to be difficult as an individual. You can imagine some operations with large amount of initial capital will start existing, operating hundreds or thousands of cars at once, with dedicated maintenance crews and so forth.</p><p>So unless governments decide to break up this <a href="https://en.wikipedia.org/wiki/Nash_equilibrium">non-optimal Nash equilibrium</a>, we can expect pretty similar patterns than those seen in cryptocurrency recently. Looking at recent history around tech innovations, the scenario laid above will almost certainly happen in most countries out there.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oDxK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oDxK!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 424w, https://substackcdn.com/image/fetch/$s_!oDxK!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 848w, https://substackcdn.com/image/fetch/$s_!oDxK!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 1272w, https://substackcdn.com/image/fetch/$s_!oDxK!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oDxK!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif" width="498" height="199" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:199,&quot;width&quot;:498,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Agent Smith from The Matrix saying \&quot;This is the sound of inevitability\&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Agent Smith from The Matrix saying &quot;This is the sound of inevitability&quot;" title="Agent Smith from The Matrix saying &quot;This is the sound of inevitability&quot;" srcset="https://substackcdn.com/image/fetch/$s_!oDxK!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 424w, https://substackcdn.com/image/fetch/$s_!oDxK!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 848w, https://substackcdn.com/image/fetch/$s_!oDxK!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 1272w, https://substackcdn.com/image/fetch/$s_!oDxK!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3e14ba9-ab4f-4ceb-a1f6-b5f5caf6b966_498x199.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h1>Business strategies</h1><p>Now that you know the future, how can you make money out of it?</p><h2>Specialized taxis</h2><p>Quite obviously those robotaxis will be mass-produced and mass-operated. Leaving very little space for specific needs that one might have. A few ideas that might stick and expand in the future:</p><ul><li><p>Hard-to-reach destinations &#8212; at least at the beginning, a lot of destinations that have unconventional roads our that are outside a well-known operational area will probably still need humans to take the decisions and operate vehicles with different capabilities</p></li><li><p>Luxury &#8212; the same way luxury shops sell you bags hand-crafted by expert artisans from a village in France, rich people will be happy to buy a transport with a human-enhanced service. Probably not driving, but instead dedicating their time and attention to the service of the passengers: serving drinks, carrying suitcases, polishing shoes or doing the hair&#8230; Your imagination is the limit</p></li></ul><h2>Optimization</h2><p>Eventually the intense competition will make this business as profitable as OpenAI is open &#8212; not at all. The difference between life and death will lie in every single cent you can optimize, and specifically in something that humans do naturally today: predict where people will be ordering taxis from.</p><p>There is apparently no particular app doing this at the moment, although there are several research papers on this topic, making it at the ideal stage to be transformed into an app: the technology exists, it just needs to be turned into a product.</p><p>Today&#8217;s drivers are probably not so interested in paying for this, but when huge players are going to be fighting for the highest car utilization possible this kind of application would be absolutely essential.</p><p>A smart way to do it would be creating today an app with existing data sources, give it for free to all taxi drivers, collect as much data as possible and eventually be ready the day robotaxis roam the streets.</p><h2>Financial product</h2><p>As said before, Robotaxis are <em>almost</em> passive assets, quite similar to the way real estate operates. You need a lot of capital, a bit of maintenance and they generate a steady income.</p><p>And just like real estate, you can expect to see both huge institutions on the market but also many oportunistic individual players with smaller amounts of money, willing to invest a few thousands and earn a percentage on it.</p><p>So you can just collect capital from individuals, assemble a fleet, a maintenance crew and start billing a percentage of this captial every month.</p><h2>Fleet management</h2><p>The financial product of course goes hand in hand with the management of the fleet. While this is not going to be much ellaborated in this article, you can expect that many tools and services will be required for the management of such a fleet. Some akin to those already existing while others might be novel:</p><ul><li><p>Dirt-cheap electricity &#8212; being one of the most prominent sources of spending, averaging the cost of electricity as low as possible will be a key</p></li><li><p>Vehicle cleanup &#8212; not only vehicles will have to be kept clean, but also you&#8217;ll have to know when to clean them: there is no way people will self-report throwing up an excess of Margaritas, meaning that some image-based assessment will have to be made after  each trip</p></li><li><p>Mechanical repairs &#8212; more than cleanup, all cars will eventually break to some extent and need to be repaired. Same as with the cleanup, the interesting question is how will you know when something is broken? More importantly, when is something about to break?</p></li></ul><h2>Country replication</h2><p>It used to be that people were excited to bring back alarm clicks from Akihabara because this technology was not available in Western countries. Globalization changed that, the same iPhone is immediately available in every single city in the world.</p><p>But this is not counting on regulations. You might or might not like the safety/innovation tradeoff made by the EU but it&#8217;s certainly creating opportunities as well.</p><p>Indeed, since these cars will be first available in other regions of the world, there will be no need even to trust this article to know what is going to happen or not. It will unfold under our eyes with the knowledge that it can&#8217;t happen yet in EU but that it will happen anyway in the future.</p><p>So for example you&#8217;ll easily be able to build up a taxi call prediction app like described above that is fed with data for major EU cities and wait for an US actor to start attacking the market for a fairly easy exit.</p><h1>Conclusion</h1><p>Beyond the hype surrounding fully self-driving vehicles, it&#8217;s interesting to see that Melon Tusk will probably be responsible for the miracle of binding Taxi and Uber drivers together into hating automated cars.</p><p>The landscape of urban transportation will be profoundly transformed into a financial asset, ensuring war, speculation and other game theory shenanigans. If you like to watch the world burn, you&#8217;re in for a fun time ahead.</p><p>This will obviously create a whole new ecosystem around it, from the financial instruments that will make it possible to the reorganized car-cleaning crews.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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[100 Ways LLMs can Boost Your Business]]></title><description><![CDATA[LLMs are not just about chat. All professions can reap productivity increase on various tasks. The only limit is your imagination!]]></description><link>https://www.baby-cto.com/p/100-ways-llms-can-boost-your-business</link><guid isPermaLink="false">https://www.baby-cto.com/p/100-ways-llms-can-boost-your-business</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sat, 13 Jul 2024 06:01:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f665c94e-eef8-49f2-bbf9-8d98ccc2ea9a_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>LLMs certainly are a breakthrough in terms of natural language processing. However the real spark that turned to world mad is ChatGPT. Before it, you could still use GPT-3, but few people outside of specialists did. It&#8217;s when the chat form factor appeared that the general public started to realize the power of LLMs.</p><p>Unfortunately, chat &#8212; or at least passing as intelligent humans &#8212; is not the main strength of this technology, which is rather a sort of elaborate parser/translator. As such, there is a million ways you could integrate a LLM into your business at different levels, optimizing 10% of someone&#8217;s job here and there.</p><p>To prove this point, today we&#8217;ll explore 100 use cases that stand besides the stereotypical uses of LLMs to imagine what you could truly do in a wide range of industries, provided a bit of brain juice and a few lines of code.</p><h1>Development and Project Management</h1><h2>Automated compliance checks in code or documents</h2><p>Any company beyond a few dozen employees ends up forced to draft policies, processes and rules that must be followed. Some of those require a big picture thinking, but some of them are precise checkpoints that can be easily checked in text-based outputs: source code, contracts, commercial propositions, etc. A series of robots could entirely make sure that the bulk of policies is indeed applied throughout the company.</p><h2>Programming language conversion</h2><p>As said  in introduction, LLMs are great at translating. But while this works amazingly for human-to-human languages, it also works quite well for programming languages. Typically, you can take any API vendor documentation in any language, get the example snippets and convert them into your current language. This also works within a given programming language to replace a specific library by another one that has equivalent features but different structure.</p><h2>Detect bug reports from user reviews</h2><p>It becomes easy to apply <a href="https://en.wikipedia.org/wiki/Linus%27s_law">Linus&#8217;s law</a>: &#8220;given enough eyeballs, all bugs are shallow&#8221;. If your product is meeting a certain level of success, people will inexorably start complaining about their frustractions online: through social media, app store reviews and so forth. Using a LLM, you can parse the whole lot of those reviews to detect if any of them actually describe a potential bug that you should care about.</p><h2>Validate business strategies against doctrine</h2><p>It is no secret that I am a fan of <a href="https://learnwardleymapping.com/">Wardley Maps</a>. The only issue being: the source material is very long and complex. A potential use for LLMs (especially long context ones) is to be able to assist you in the map creation but most of all to check that your predictions and projections are actually taking into account all the rules from the 800 pages of the book.</p><h2>R&amp;D progress audit</h2><p>It is always tedious to document R&amp;D as the nature of it asks to iterate rapidly between various experiments. However if you were to centralize all your results in a semi-formal way, you can imagine have a LLM take over this reporting process and generate exact day-by-day reports of who did what, what are the conclusions and what are the next things being tested. Extremely convenient in the case of grant justification as well.</p><h2>Task break-down and planning</h2><p>Why are developers always so late? Sometimes, it&#8217;s simply unforseeable problems popping up, but most of the time &#8212; and especially for juniors &#8212; it&#8217;s because they fail to decompose the tasks that they have not already done. If you never did something, your brain will probably ignore all the sub-tasks that you will have to accomplish. A LLM could be a good help to break down a given task until all the steps and dependencies are clear.</p><h2>Natural language programming</h2><p>Instead of having to code a specific behavior from a software component (email filter, automation platform, data ingestion platform, etc), you could simply specify what you want in plain human language and have it transformed into code under the hood.</p><h2>Drive processes (CRM, issue tracking, etc)</h2><p>Having a system read all your emails, messages and so forth will definitely be a privacy challenge, but on the other hand this could enable automatically reporting status updates and changes to CRMs, issue trackers and so forth. For example you could analyze the Git history to move an issue&#8217;s status (alongside with comments explaining what happened). Or track commercial emails to automatically report on a lead&#8217;s status.</p><h2>Run end-to-end tests of applications written in natural language</h2><p>Isn&#8217;t that so fucking annoying to write front-end tests? This could change with appropriate use of LLMs. They could not only write tests for you but &#8212; and most importantly &#8212; they could also heal existing tests to adapt for code changes.</p><h2>Visually test applications</h2><p>LLMs can have vision capabilities. As such, they are able to do something more smart than a pixel-perfect validation. They could check two images and tell you if there are significant differences. Look at a web page and tell you about obvious issues (text overflowing, alignment problems, etc).</p><h2>Log analysis to detect abnormal behaviors</h2><p>Server logs are usually very long files that you keep to be able to diagnostic a particular issue if it happens, but when it&#8217;s about knowing what happens in real time then it becomes more complicated. Log monitoring tools exist but they are limited by the fact that logs are extremely diverse and unexpected. Instead, LLMs  could be used to read all logs in real time and raise alerts when needed.</p><h2>Threat modeling assistance</h2><p>How do you secure a product? Nothing can be considered secure in the absolute, best practices are only good as long as they fit your needs. That is why you need to <a href="https://owasp.org/www-community/Threat_Modeling">model your threat</a>, which basically comes down to finding the weakest link in all the components holding the product&#8217;s security and figuring which might break easily enough for the prize to be worthy of the effort. This requires to imagine a full dependency map of everything related to the product, which a LLM could help enumerate.</p><h2>Open source issue qualification</h2><p>Open source projects historically always had issue with bug reports and feature requests, that are often done in a terribly unclear way. A robot could on the other hand be able to assist people in doing their report, until the produced description is clear enough for all parties.</p><h1>E-commerce</h1><h2>Image-based search</h2><p>Classical e-commerce facetted search requires detailed product description with a structured model of the product&#8217;s characteristics. And while for a stick of RAM this might be kind of easy, for some fields like clothing for example it&#8217;s already harder to categorize <em>everything</em>. On the other hand you could be asking questions about images, like &#8220;I want a pair of blue jeans with a contrasting seam&#8221; and the search engine could smartly filters images on this unexpected characteristic.</p><h2>Mix-and-match assistant</h2><p>Imagine that you find your perfect pair of pants but you are looking for a shirt to go with it. A LLM would be able to understand the level of formality, the color and the style of those pants and then to find a matching shirt for it. Let&#8217;s note that it&#8217;s a different concept from &#8220;recommended products&#8221; that exist today: here we consider the user&#8217;s explicit intention. This works for all kinds of products: cosmetics, food, tools, etc.</p><h2>Organize products from raw pictures and spec sheet</h2><p>Imagine that you are building a e-commerce in which you have raw material for each product that are pictures and PDF datasheets. You could have AI take care of creating categories, structured product characteristics and product description completely automatically, only leaving humans for review.</p><h2>Product composition decoder</h2><p>Imagine that you are lactose-intolerant and are looking to buy food. Or your skin has some specific alergies to chemicals. It would be interesting to be able to ask those questions to the e-commerce directly, which will decode tricky product compositions for you. Or even better, state in your profile which components you wish to avoid and the system will automatically put a warning tag on all corresponding products, along with a warning before checking out.</p><h2>Product suggestion</h2><p>You are redecorating your terrace and you need to figure what to put there. Send a picture of it to your furniture store and have directly matching suggestions displayed to you. It also works for various cases where the user could state a problem: &#8220;my computer is too slow&#8221;, &#8220;I need to water my tomatoes&#8221;, etc.</p><h2>Visual audit of second-hand products</h2><p>Since LLMs are able to view and to follow instructions, second-hand platforms could specifically ask to visually check known defects on pictures. This could help the user into qualifying their own product, as well as highlight important checkpoints to customers.</p><h2>Price suggestion for second-hand platforms</h2><p>In the same vein of being able to analyze products visually, you could as well automatically compare a given product to similar products sold in the past and suggest from there a fair price completely automatically.</p><h2>Extract and categorize pain points from online reviews</h2><p>Online reviews are a trove of user feedback for some products sold beyond a certain scale. Using a LLM to systematially parse them can be an interesting way to find out defects, use cases, quantify perception through time, etc.</p><h2>Faceted search</h2><p>Most e-commerce websites have what you call faceted search. It&#8217;s those filters on the left that allow you to refine a listing by some characteristics whether it&#8217;s size, color or anything else. Sometimes the experience is great but sometimes it is also not super smart. A way to improve the experience wouuld be to have a search bar that lets you specify in natural language the filters that you want to apply and then let the AI translate into the right request. No more awkward clicking, scrolling and waiting for page load again and again.</p><h1>Entertainment</h1><h2>Drive NPCs &#8212; basically, Westworld</h2><p>The Westworld show was pretty good &#8212; at least season 1 &#8212; at showing us instinctively what AI could accomplish for us and how it could do it. Give structured scenarios to <a href="https://en.wikipedia.org/wiki/Non-player_character#:~:text=A%20non%2Dplayer%20character%20(NPC,rather%20than%20by%20another%20player.">NPCs</a> and let actual player interact with them. LLMs can entirely be used to generate dialogues, figure the steps to stay on the scenario, etc. Potentially very exciting amusement parks in perspective, but also of course video games.</p><h2>Generate backstories and character sheets for RPGs</h2><p>If you are a RPG player &#8212; like D&amp;D and the sort &#8212; you probably know that getting your character off the ground can be a lengthy process. Generate a backstory, specs, etc. It&#8217;s hours spent doing administrative procedures instead of playing. Instead you could just prompt the basic concept of the character and have it all generated in an instant.</p><h2>Assist users learning how to play a game</h2><p>Board games are always hard to understand the first time you play them. You could however imagine that an LLM-boosted agent could understand those rules and help beginners to play: explain what happened, let them know of potential moves, etc.</p><h2>Answer questions about movies halfway</h2><p>Sometimes in the middle of a movie you are just lost at what happened. However platforms already have a lot of data a LLM could exploit, like subtitles for example. Using this, you could imagine asking Netflix to clarify specific plot points and have the system check the transcript of the movie thus far to help you understand.</p><h2>Image culling and storytelling</h2><p>Ever came back from holidays with thousands of pictures that you never actually sort through? LLMs would be good at making a consistent story and picking the top X pictures to tell it in your album.</p><h2>Book, podcast, etc. length or style adjustment</h2><p>I personally hate reading fiction. For some reason, I&#8217;ve been devouring wikis and theories from GoT, LOTR and so forth but never actually managing to finish the books. It&#8217;s too long and too indirect. What if book &#8212; and podcast, news, etc &#8212; platforms let you adjust the length and style of what you are reading? 50-pages version of GoT? 2 minutes, to-the-point version of a 20 minutes podcast? The ability to further explore topics that piqued interest? Lots of people already watch movies in 1.5x, this would only be a logical next step.</p><h2>Trope analysis and novelty factor</h2><p>Star Wars episode IV is always a good example of how contextual movies need to be. Watch it in 1977 and it will fucking blow your mind. On the other hand I&#8217;ve shown it recently to a friend that was like &#8220;oh come on and then it&#8217;s going to be his father? how fucking original&#8221;. If you want to make a movie or an article entertaining, it must be composed of a good mixture of things that people are used to, spiked with an edge of novelty. Using AI to systematically explore and quantify tropes in existing scripts can help establish the novelty factor of a new project. Let&#8217;s note that this also works for politics, journalism, fiction and basically anything targeted at the mass market.</p><h2>Auto-edition of video interviews</h2><p>Interviews are a significant pain in the ass to edit. But using a LLM you could transcribe everything said, ask for it to pick the best part that will fill up X minutes and automatically slice and edit the video at the proper timestamps.</p><h2>Conspiracy theory generator for social media</h2><p>Whether we like it or not, social media is full of trolls trying to influence people&#8217;s choices and votes. A way of doing this is to attack specific pillars of a society (science, government, etc) by throwing an insane amount of conspiracy theories to destroy them. It doesn&#8217;t need to be consistent, it just needs to be massive. That is great, given that LLMs are excelling at making text that <em>sounds good</em> but that is utterly shallow. Pick your target, throw a LLM at Twitter and enjoy a massive ideological destruction.</p><h2>Fan-fiction generation</h2><p>Fans usually like their media so much that they want to keep exploring this world endlessly. Without making those stories canon, entertainment giants could easily generate literally endless stories by fine-tuning LLMs on the specific do&#8217;s and don&#8217;ts of a universe and let them generate content for their fans. As a bonus, the most successful stories could serve as a basis for major projects.</p><h1>Data Analysis</h1><h2>Data visualization</h2><p>Data visualization is a hard topic in the sense that managing all those graph libraries, SQL queries and the weirdest APIs like Pandas, it&#8217;s not very accessible to your average executive Joe. On the other hand LLMs are <em>excellent</em> at this, given a proper human intent. They are going to play a key role at making data more accessible.</p><h2>Transform natural language signals into structured data</h2><p>Scrape social media, listen to Slack messages or emails and turn this into structured data that you can quantify and analyze easily through graphs and statistics.</p><h2>Loosely structured data cleanup</h2><p>How many times data is provided in CSV form with completely inconsistent content? Poorly escaped lines, inconsistent IDs, etc. A usually tedious cleanup job could be entirely automated away with a properly trained LLM.</p><h2>Reverse-engineer structures</h2><p>Have you ever tried to understand what a company does from the outside? It&#8217;s usually very hard, given that the corporate website will tell you that they &#8220;deliver excellence&#8221; across a wide range of industries, present their &#8220;solutions&#8221; and &#8220;case studies&#8221; but will never go into the detail of <em>what</em> they actually did. The best way to understand the truth in my opinion is to look at job descriptions, both their quantity and their content. Gather them all together and you understand exactly which operational tasks, tools and hierarchy those companies have. Tedious by hand, but very suitable for LLMs to complete.</p><h1>Natural Language Processing</h1><h2>Translate</h2><p>All right this one is obvious in a conversational setup, but it of course also works if you are trying to internationalize a service. In an e-commerce or social media for example, the level of translations from a top LLM is good enough that you can trust it unsupervised in many languages for many non-critical use-cases.</p><h2>Generate alt tags</h2><p>Something that all CMSes should start doing: automatically generate alt tags for their image library. LLMs are now entirely capable of describing an image, and it&#8217;s so good for SEO and accessibility that this should become the norm very quickly.</p><h2>Spellcheck</h2><p>LLMs are also very good at spell-checking and can be used in a wide range of applications to help you improve your writing.</p><h2>Find acronyms</h2><p>The hardest thing when starting a project is to find a good name for it. Well not anymore, as now you can simply describe what your project does, ask Claude for a fitting acronym and there you go!</p><h2>Parse free-form numbers</h2><p>It&#8217;s not uncommon to end up with a data table where you need to parse prices or different kind of amounts but unfortunately they have been given in various forms, like &#8220;30 millions&#8221; or &#8220;45k&#8221;. While you can solve this with regular expressions, a cheap LLM can often be very efficient at parsing this.</p><h2>Anything to Markdown</h2><p>Given the ability of LLMs understand documents structure &#8212; textual or from images &#8212; they are excelling at producing markdown from anything. Just rasterize your PDF, throw it into a LLM and you&#8217;ll get your markdown version pretty easily.</p><h2>Parse citations from academic papers</h2><p>My understanding is that academic parpers follow a formal structure but in a semi-formal way technically speaking. Typically they are all linked to each other through citations, but their parsing is tedious. LLMs could empower this.</p><h2>Smart replace in document</h2><p>Imagine you write a long proposal for a client and refer repeatedly the name of their product or some important concept. But then your boss swoops in and asks you to remove or change all those references by another one. Sometimes search and replace can do the job, but sometimes it will affect the grammar or the structure of sentences. LLMs could do this job completely automatically.</p><h2>Auto-adaptation of texts for different targets</h2><p>Imagine writing a scientific revue. Maybe you want to address different levels of readers from the most advanced to kids. Or imagine a publisher that wants to make Shakespeare accessible to foreigners. LLMs are able to translate between languages but also between styles.</p><h2>Re-phrasing of customer input</h2><p>Customer support is a fantastic world where you get insulted for things you didn&#8217;t do. Instead, LLMs could act as a buffer between the customer and the support where aggressive, sarcastic sentences are turned into plain and clear ideas.</p><h1>Content Generation and Management</h1><h2>Generate FAQ from website content</h2><p>Gather all the content of your website, figure all the questions that it answers and generate the FAQ pages from this.</p><h2>Generate decent usernames</h2><p>It is quite hard to generate a decent username when subscribing to a platform. With a few smart questions and methodology, a pretty cheap LLM that could even run locally would produce many interesting name propositions in real time.</p><h2>Create recipe/tutorial variations</h2><p>When cooking, doing some work in your home, taking care of your garden or anything hobby-level in which you have no particular expertise, you will tend to follow tutorials to learn how to do things &#8212; and more importantly to achieve particular goals. The only issue with those tutorials is that they might have details incompatible with your particular situation. For example you want to cook a cake but you are alergic to one particular component. How do you replace it? That&#8217;s where the LLM can make educated guesses and alter the content dynamically to fit the user&#8217;s need.</p><h2>Smart filling of templatized documents</h2><p>Newsletter software allows you to place people&#8217;s name and a few other details within the text. But what if you could go much further than that? Create templates for documents like contracts, commercial outreach, etc. Then have a LLM fill up the blanks respecting grammar, gender or even making up whole sentences based on meta information: &#8220;Hi John, you expressed on our contact form that you need XXX, which can be filled by products in your YYY range. Let&#8217;s schedule a call?&#8221;.</p><h2>Generate onboarding procedure and training path</h2><p>Anyone running a company knows that transmitting the company&#8217;s knowledge is a tedious endavor. Pages and pages of process have been written over the many years of existence of the company, all at different levels of maturity. How do you introduce a newcomer to all this in a consistent order? You can feed all your documents to a long context LLM (like Gemini&#8217;s 2M tokens) and have it sort out documents in topological order and that are interesting in respect to a given job description.</p><h2>Organize asset production based on company policy</h2><p>Many companies have a process for rolling out a product or communication: social media assets, press releases, etc. While generating them directly will still be a human work, a LLM could allow high-level definition of guidelines in plain text, with more nuances possible than regular automation platforms, and automatically create outlines for the assets that need to be created.</p><h2>SEO and keyword-centric upgrade of articles</h2><p>CMS and other content management tools could receive specific directives regarding SEO and keywords that need to be present to perform not only live audits but also suggestions of modifications to the content in order to integrate the desired keywords.</p><h2>Meeting prep, create meeting agenda</h2><p>What worse than a poorly prepared meeting? Gathering information from previous meetings, ticket trackers and other digital platforms, an AI could outline the agenda of upcoming meetings, while at the same time helping each participant to gather their own content to present.</p><h2>Auto-update documentation</h2><p>All products and company processes need to be documented at various levels from the most technical to the most high-end. As the product grows and changes are made, it becomes hard to keep track of what needs to be updated in the documentation. Combining LLMs and embeddings,  you could track the overall company activity and highlight parts of the documentation that become obsolete, list the missing parts and even automatically propose edits.</p><h2>Dynamic course re-writing</h2><p>Imagine a student learning online in front of their computer. Some topics will be easy but assuredly some others will prove more challenging. These courses are often evaluating the student&#8217;s skills all along the way. What if depending on those evaluations the content of the courses was adapted to the strengths and weaknesses of the student? Catch-up texts can be generated from the original course but focusing on the weaknesses and ellaborating on them further than in the initial content.</p><h2>Infinite copy generator</h2><p>How do you know which words are going to transform your audience best? What if you generated one version of your content for every single time that someone reads it? Then observe which versions worked the best and use this as reinforcement for your model, to produce more and more efficient versions of the copy.</p><h2>Dynamic content</h2><p>In the same vein, you can also observe the user&#8217;s behavior and browsing history in order to dynamically re-write or optimize pages when he lands there. Connect the dots with concepts freshly ingested, push forward detected interests, etc.</p><h1>Image and Visual Processing</h1><h2>Transcribe handwritten notes</h2><p>This might sound like a miracle but GPT-4o is able to read my handwriting. Not only this but it can transform it into a well-structured Markdown document. And then of course translate, summarize and all the perks. This can be helpful in number of scenarios from digitizing meeting notes to processing and translating on-the-fly antique manuscripts.</p><h2>Pet control</h2><p>Pets tend to behave differently when their owners aren&#8217;t home, like jumping on the bed or sofa. LLMs are definitely not the most efficient but they are for sure the easiest way to express to a machine &#8220;if a dog rolls in my sheets yell at them to stop&#8221;.</p><h2>Generate color palettes</h2><p>Just like LLMs are trained on word patterns, they are trained on visual patterns and including the understanding of colors. This means that you can generate smartly color palettes that actually work (as opposed to this color wheel madness you often see). This can help you generate your own UIs but even more than that what if the LLM were able to generate all the design tokens up to the user&#8217;s taste, ending up with a unique, custom and beautiful UI for every single user?</p><h2>Art explanation</h2><p>If like me you are art-illiterate but still end up in museum wondering what happened in a specific painting, only to find the name of the painter with a vague title next to it, with a lengthy audio guide telling you everything except what you want to know&#8230; you&#8217;ll understand this idea. Instead of audiobooks, musuems could provide interactive assistants fed with in-depth knoweldge on every work of the musuem but able to distil it in a way tailored to the visitor&#8217;s taste and to reply to their questions directly.</p><h2>Picture-based food search</h2><p>Google Maps is trying very hard to create ontologies of the real world, especially with its &#8220;questions&#8221; program asking you if a given service or food is available in various places that you have visited. However if you are not american you probably ended up confused when you got asked if your local high-end bakery was making smores. Food simply does not translate between cultures. That&#8217;s where a deep understanding of images could lead to a much more efficient search that would echo one&#8217;s way of expressing their wants.</p><h2>Better narration for GPS</h2><p>Did you ever take the Madrid highway with some US-optimized GPS voice? How long did it take you to take the wrong turn? With ample imagery available &#8212; street view, 3D maps, etc &#8212; you could absolutely have much more descriptive directions from the GPS. Referring landmarks, taking into account perspective, etc.</p><h2>Drone or CCTV-based visual inspection of equipment or land</h2><p>As you can describe what you want to see, you can have drones or cameras film something you want to inspect and ask the LLM to tell you if it matches your expectations or not. Look at satellite imagery and ask &#8220;tell me places where forrests have been depleted&#8221;. Look at a building and say &#8220;tell me if any tile is missing&#8221;. And so forth.</p><h2>Auto-design simple, templated flyers, posters, etc</h2><p>Some apps will help people organize events or do marketing. Especially for small businesses it&#8217;s going to be hard to create those assets on their own, as they will not have the means to work with bigger agencies and are most likely unaware of best practices. On the other hand the app could leverage LLMs to apply best practices, pick colors, use and customize proven layouts to generate all kinds of visuals.</p><h2>Check that translations are meaningful in context by visually analyzing apps</h2><p>A common example of translation error that infuriates me is around the word &#8220;check&#8221; in English that can be understood as two distinct French words: either as in &#8220;verify&#8221; or as &#8220;check this box&#8221;. And very often, the meaning is lost, leading to crazy translations like &#8220;Verify the terms and conditions to continue&#8221;. Since LLMs can read texts and context, they could be used to apply translation files on an UI and make sure that all buttons make sense.</p><h1>Document Processing</h1><h2>Parse invoices</h2><p>Invoice management is the bane of any small business. You receive hundreds of them, need to extract different items and taxes systematically, but on the other hand every single invoice has a different format. Fortunately LLMs are pretty good at extracting this information and putting it into a JSON &#8212; whether it comes from an email, a PDF, a picture of a ticket, etc.</p><h2>Pick food at restaurant</h2><p>Did you ever end up undecisive at a restaurant? Just snap the menu, feed it into a LLM and let it guide you into ordering something. It even works with hand-written texts that you can&#8217;t understand &#8212; Japan explorers will rejoice. If you are a restaurant you can even push this further and help users through a custom assistant.</p><h2>Normalize recipes</h2><p>As a nutrition app or related, you might want to make the link between the food listed in a recipe and the calories for example. But people writing recipes love to use the weirdest units or even have things implied &#8212; like some common ingredients not even being listed as ingredients. With the help of LLMs you can extract these ingredient lists, transform them into units that make sense and get the nutritional value of what you are cooking.</p><h2>Convert mind-maps to structured linear document</h2><p>Mind maps &#8212; or the Post-It method as well &#8212; produces a lot of ideas around one given topic but you might end up overwhelmed at the end of the process by the amount of information that needs to be processed. LLMs can transform those ideas into a linear structure, properly sorted and organized.</p><h2>Paper forms digitalization</h2><p>As an intern I have been copying lots of paper forms made on-the-spot for fidelity cards in a store. Or recently, we all have been filling up countless COVID forms whenever taking the plane. Using LLMs, you can understand and transcribe those forms completely automatically into a digital system.</p><h2>Transcribe, tag and reference historical paper-only archives</h2><p>Countless historical documents or books have been scanned but how many are properly referenced? You can guess that over thousands of years of history, we could set to map out all those documents, link them together, analyze references and ideas over time, to build a better understanding of our history and our currents of thoughts.</p><h1>Customer Support and User Experience</h1><h2>Start workflows from emails</h2><p>Customer supports will often be drowning in emails. You can parse them, detect intents and trigger the proper systems in your back-office to start procedures, without any human intervention.</p><h2>Request routing inside the company</h2><p>When the organigram starts becoming big, it might be hard to navigate the responsibilities and knowledge of the people in there. Especially for newcomers, it cn be a challenge to find the right person to talk to while also not bothering them unnecessarily. As CTO and founder I can answer most questions on most topics within my company, but should an intern come and ask me how to connect the printer? A reassuring AI could help people orient themselves in the hierarchy to know who they can confidently reach out for in order to receive help.</p><h2>Prioritize incoming messages and notifications</h2><p>You are probably like everyone else drowning in countless useless sollicitations, from services to which you subscribed 20 years ago to urgent business emails. Depending on the time of the day and your personal goals, you might want to be notified of one thing but not the other. Or you might want to receive notifications in bulk for some topics. For example I&#8217;d love to see Slack create a &#8220;what do you want to be notified about?&#8221; option and then burry irrelevant mentions and messages.</p><h2>Configure complex features</h2><p>When you use some apps, there will be features that are extremely complex to grasp. For example, try any product in Binance, it&#8217;s complex enough to throw you off if you are not eager enough to learn about it. Through the use of AI they could instead ease the user into setting the right parameters according to their own personal goals.</p><h2>Voice message summarization</h2><p>Some people love voice messages, some people like me are loathing them. Having an AI skip through the &#8220;sorry I&#8217;m sending you a voice message because I&#8217;m in the street and it&#8217;s easier to send a voice message [&#8230;]&#8221; and instead deliver to you just the point of the message would be a great WhatsApp addition.</p><h2>Conversation coach</h2><p>We are constantly exposed to conflictual situations, especially in low-stake but annoying uses cases like negociating a refund overe an incorrect package received. Email and messaging apps could help you understand what you could obtain in that situation and redact emails for you, helping you every step of the way and reducing your mental load.</p><h2>Automated test grading</h2><p>The point of MCQs is that they are easy to grade, including if done by a computer. That&#8217;s why e-learning platforms use them so much. But given the advances of LLMs, it would be easy to imagine having them grade even textual responses, looking to see specific bits of information and telling you if it&#8217;s correctly explained or not.</p><h2>Interpretation of complex diagnostics</h2><p>Some diagnostics are not nice to hear, especially when they are particularly complex. From medical reports to SEO audits, if you are not an expert you might be confused by the terms and implications of those documents. A properly trained LLM could instead simplify them for you and even answer potential questions you might have.</p><h2>Allow customers to do self-diagnostic on products</h2><p>Vice-versa, some products are complex and have many failure modes. Companies internally have debugging procedure that can pin-point exactly what is faulty, but it&#8217;s hard for the regular customer to follow such procedures. Instead of paying a human being to tell you to turn it on and off again, such workflows could be assisted entirely by a LLM, specially driven by a tailor-made logic engine for your product.</p><h2>IT support for end-users</h2><p>The most feared and annoying department of a company is often the IT, that has the important task of securing the company&#8217;s data and intellectual property while also having to explain to users how to connect the Wifi. By the proper use of LLMs, with their general knowledge of how computer works, but with a specific training adapted to the policy, they could skim a lot of useless requests off the pile from IT departments.</p><h2>Suggest A/B testing variants</h2><p>A/B testing is great to test how the user is going to react to different UX or copies, but how might you do it? You need the ideas, after all. A well-trained model that knows the UX best practices for different industries could do this job of taking a human&#8217;s work and proposing potential optimizations.</p><h2>Algorithm transparency</h2><p>Many complex algorithms are ruling our lives. For example every electronic payment goes through a set of rules to determine if the action is legitimate or not. These departments are utterly closed and opaque to the rest of the company. Typically, if your card gets blocked then nobody in the bank can tell you why nor for how long it will stop working. Having a LLM being aware of the different rules of the algorithm, it could explain in simple words the reasons of this block to the bank advisor, and the available perspectives. This works for banking, but any sector with complex algorithm could leverage this.</p><h1>Personal Assistance</h1><h2>Help user stay on plan</h2><p>So many apps are helping us become a better version of ourselves, wether it&#8217;s for diet, exercise, jet lag, pet training, etc. But how often can you follow 100% of the plan? With a bit of intelligence you could let users report their deviations and help them stay on track without overreacting with counter-productive actions or simply getting demotivated.</p><h2>Context-picking for events, emails, etc</h2><p>Imagine an event in your calendar with few details. When the event comes up, the system could read your emails, meeting notes talking about this event and then infer useful information ranging from the latest tickets from the issue tracker, the weather if you need to go somewhere, remind you to take your IDs or advising you to dress in a certain way. Overall, for one item and a lot of context, the LLM could pick the top few elements that are relevant for you not to forget &#8212; wheter it&#8217;s an event, an email you are writing, a plane ticket, etc.</p><h2>Long-term goal tracking</h2><p>The human brain is very wired to small tasks and has a hard time taking a step back to see if you are achieving your long term goals. On the other hand an AI could be aware of your goals and rank each of your actions telling you if they seem to be helpful or not to achieve that specific goal.</p><h2>Natural language passwords</h2><p>Passwords are a notoriously hard problem. How do you make a password that is secure yet that you can remember? You could imagine generating complete phrases through LLMs but not only. When the user types back the phrase, you could use LLMs to normalize the text before hashing it so that spelling mistakes or punctuation or even word arrangements do not affect the outcome of the hashing.</p><h1>Business and Legal</h1><h2>Categorization of items</h2><p>The other day I wrote an article about GDPR, which parsed a big HTML page from the CNIL. The information there was semi-structured and I had to categorize things further in order to make sense of them. Same for the current article, the different ideas have been categorized by a LLM. This is a great tool to group similar concepts together.</p><h2>Critique political programs</h2><p>While LLMs are obviously biased &#8212; especially with the US culture wars &#8212; but are nonetheless able to project without ego into many persona. As such they are quite interesting to tools to use in order to review political programs and see how they are backed by facts and theory. Journalistic platforms could enhance their content with thorough review of every single politician, detect their parting from party ideas, and most important let people explore concepts on their own, for their personal situation or their vision of society.</p><h2>Find out adequation between candidate and job description</h2><p>Large companies will match candidates only based on keywords based on a first pass. However we know how biased this approach is, given specific technical knowledge is not shared by recruiters &#8212; and even less by those in charge of unpiling thousands of CVs, which must not be the highest ranking ones. On the other hand AI is great at matching a CV to a job description, describing quite well the fitting and lacking areas as well as the challenges to work with this person. Even further, based upon a transcript of the interview, you can ask questions and validate specific checkpoints by searching intelligently for the relevant parts, without having to listen to hours of recording.</p><h2>Check ToC exhaustivity</h2><p>When you reply to a RFP, a grant or any exercise of that style, there will be a list of requirements you need to meet and precise points that need to be addressed. Obviously it is more subtle than just filling up a form, you need to make sure that various aspects are answer consistently throughout the response. You can use a LLM to both extract from the RFP the list of points that need answering &#8212; or at least cross-check it &#8212; and also to check if your response provides adequate light on each of those elements.</p><h2>Insurance claim/policy matching</h2><p>Insurance policies are always a bit obscure. A well-trained LLM could allow customers to role-play use cases before subscribing, as well as gather all the necessary information in case of a real claim.</p><h1>Social Media and Content Moderation</h1><h2>Automated content moderation</h2><p>As OpenAI has proven to us with its extremely restrictive usage policy, LLMs can be used to detect offensive content &#8212; or any kind of content that you don&#8217;t want to see, offensive isn&#8217;t the same for everyone. In a day and age where social media operates at a great scale, being able to detect &#8220;forbidden&#8221; content would not only make the platforms safer but also more customizable. Indeed, what if instead of having one single policy, different communities had their own policy automatially applied? Free speech and safety for all!</p><h2>Social media filters</h2><p>In the same idea, what if instead having algorithms sorting your feed in the most opaque way, you could express what you want to see? The same as TweetDeck allows you to do by keywords for example, but with concepts instead. &#8220;Tell me all about space news&#8221; or &#8220;I&#8217;m sick and tired of meme X&#8221;. On top if filtering this could also mean groupping: different posts talking about the same topics could be groupped or even hidden after a threshold.</p><h1>Specialized Applications</h1><h2>Ask questions about meeting transcript</h2><p>Summarizing a meeting is good, but being able to look for specific information in it is the killer feature. &#8220;What did we conclude on the topic X?&#8221;. This is what I really want to see in those AI meeting platforms, especially to be used during ulterior meetings.</p><h2>Step assistance in tutorials/recipes</h2><p>When following a tutorial or a recipe, some steps that might seem obvious to the person writing it will probably be hard for you to follow if you are too new to the topic. Having a LLM to be able to write sub-steps to fill the gaps for you will be a great help.</p><h2>Democratic platforms for citizen engagement</h2><p>Politicians love to claim that they know what their people want, but how do they really know? With AI&#8217;s capability to categorize and summarize, you could turn griefs and ideas into structured input coming from the whole nation. A super-simplified procedure where you could complain about anything or ask for any change as it goes through your mind. Then processed and presented in any level of detail to your representative.</p><h2>Real-estate property auto-description</h2><p>So many platforms allow to post real-estate ads, but the quality of those is often mediocre to non-existent. What if using the proper context based on the pictures, the map information, the neighborhood meta-data and so much more, you could generate a proper text description highlighting the strengths and weaknesses of a given property?</p>]]></content:encoded></item><item><title><![CDATA[A review of GDPR sanctions]]></title><description><![CDATA[How is the flagship of the world's "regulatory superpower" faring after 6 years of application?]]></description><link>https://www.baby-cto.com/p/a-review-of-gdpr-sanctions</link><guid isPermaLink="false">https://www.baby-cto.com/p/a-review-of-gdpr-sanctions</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Thu, 27 Jun 2024 07:00:53 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3ccb916e-437e-4e7b-b851-79a68db4d676_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It is said that Europe is blocking innovation with its regulations and especially with the most visible tip of this iceberg: GDPR. In effect since 2018, it regulates at European level the way we deal with Personally identifiable information (PII). The goal is to protect the privacy of all European citizens against all potential nuisances whether we&#8217;re talking of abusive marketing strategies or utterly insecure data storage that eventually ends up sold on the darknet.</p><p>The goal of this article is not to review if this measure is efficient but rather what is the impact for business. The French agency, the CNIL, keeps a list of <a href="https://www.cnil.fr/fr/les-sanctions-prononcees-par-la-cnil">all given sanctions</a> through time. We will use an <a href="https://github.com/Xowap/gdpr-stats">AI-pumped parser</a> and a bit of <a href="https://colab.research.google.com/drive/19il53J1G0DyzliZnvZtlgmf8rJmIjvY6?usp=sharing">data science</a> to analyze the past of GDPR sanctions. It is all open-source so that you can check the methodology and report issues if any.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!smSJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!smSJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 424w, https://substackcdn.com/image/fetch/$s_!smSJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 848w, https://substackcdn.com/image/fetch/$s_!smSJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 1272w, https://substackcdn.com/image/fetch/$s_!smSJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!smSJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg" width="350" height="260.8173076923077" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1085,&quot;width&quot;:1456,&quot;resizeWidth&quot;:350,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Survivorship bias - Wikipedia&quot;,&quot;title&quot;:&quot;Survivorship bias - Wikipedia&quot;,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Survivorship bias - Wikipedia" title="Survivorship bias - Wikipedia" srcset="https://substackcdn.com/image/fetch/$s_!smSJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 424w, https://substackcdn.com/image/fetch/$s_!smSJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 848w, https://substackcdn.com/image/fetch/$s_!smSJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 1272w, https://substackcdn.com/image/fetch/$s_!smSJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc39c20af-f502-4704-bbc1-6b2e907251ac_1427x1063.svg 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">An illustration of the <a href="https://en.wikipedia.org/wiki/Survivorship_bias">survivor bias</a>, to keep in our considerations in this article</figcaption></figure></div><p>Fair warning however, as always with statistics they are merely matching a story their writer wants to tell. Your company can be prosecuted on any given point of the law and the distributed fines are as much a reflection if the current state of the industry than of the CNIL&#8217;s priorities. If nobody had Consent Management Platforms (CMPs) in place, the rate of fines on this topic could be higher, for example.</p><p>Given our goal of figuring what are actually the things that will get you fined, a decent first question to look at is the rate of companies getting fined. If only a few every year there would be nothing to worry about, but if the practice is widespread then it becomes a bit more scary.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5x7O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5x7O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 424w, https://substackcdn.com/image/fetch/$s_!5x7O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 848w, https://substackcdn.com/image/fetch/$s_!5x7O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 1272w, https://substackcdn.com/image/fetch/$s_!5x7O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5x7O!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png" width="1200" height="593.0635838150289" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:684,&quot;width&quot;:1384,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5x7O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 424w, https://substackcdn.com/image/fetch/$s_!5x7O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 848w, https://substackcdn.com/image/fetch/$s_!5x7O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 1272w, https://substackcdn.com/image/fetch/$s_!5x7O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd939fe06-312d-4eb0-8ba1-11b1d9937c77_1384x684.png 1456w" sizes="100vw"></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">Total and count of CNIL sanctions since GDPR was created</figcaption></figure></div><p>Two things come up as striking from this graph:</p><ul><li><p>There is a huge spike in 2021 in terms of the sum of sanctions. This year CNIL woke up and chose violence against the GAFAM. Google and Facebook received fines of respectively 150 and 60 million euros for their cookie policies. The rest of fines is actually pretty moderate.</p></li><li><p>The total amount of fines given is increasing seemingly exponentially through time, while the total collected value is decreasing. This is raising the next question: what exactly is the distribution of those sanctions?</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e6v2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e6v2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 424w, https://substackcdn.com/image/fetch/$s_!e6v2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 848w, https://substackcdn.com/image/fetch/$s_!e6v2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 1272w, https://substackcdn.com/image/fetch/$s_!e6v2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e6v2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png" width="1294" height="984" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:984,&quot;width&quot;:1294,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;: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_!e6v2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 424w, https://substackcdn.com/image/fetch/$s_!e6v2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 848w, https://substackcdn.com/image/fetch/$s_!e6v2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 1272w, https://substackcdn.com/image/fetch/$s_!e6v2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ffa0244-5dde-4e62-b9e0-f74660775ea4_1294x984.png 1456w" sizes="100vw"></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">Heat map of sanction values through the years</figcaption></figure></div><p>Now is probably a good time to point out that in the world of GDPR, fines are mostly proportional to the revenue of the company. They are sized to be painful for your business whilst also not endangering it. Seeing the fined amount is a good way to realize which sizes of companies are being sued. This is also why this article mostly avoids counting the absolute value of fines, as it would not be comparable between cases.</p><blockquote><p><em>Note</em> &#8212; All fines in 2018 are in the 0-1k slice because on the CNIL&#8217;s page amounts are not written for 2018. But it&#8217;s not too problematic in the sense that most of what we are looking at is the count of sanctions rather than their amount. This will definitely create some noise further down, however.</p></blockquote><p>The 1M+ slices represent mostly big companies (Google, Amazon, Yahoo, Criteo, &#8230; you see the kind). Those are notoriously invading privacy of individuals at a massive scale, which explains some constant action in that range. But in comparison to the bulk of the activity this looks pretty exceptionnal. Let&#8217;s focus more on the bulk of the sanctions.</p><p>In that regard, the 100k-1M column &#8212; which represents national companies (TV channels, telcos, etc) &#8212; is definitely having some constant action. It got dilluted in 2023 but the absolute value stays equivalent. This will be the most interesting slice to unfold.</p><p>And finally you can see a sharp 2023 increase in the 1k-10k slice &#8212; small companies such as web agencies &#8212; meaning that this raise in sanctions counts that we have seen in the first graph can be attributed to an increased focus on smaller actors.</p><p>This looks to be the first major shift in strategy since the beginning: since 2023, small actors are being targetted at a significantly increased rate while large corporations where the previous focus.</p><p>But what are those sections about? Is it all about cookies, or is there more to this law than CMPs?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!50kN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!50kN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 424w, https://substackcdn.com/image/fetch/$s_!50kN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 848w, https://substackcdn.com/image/fetch/$s_!50kN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 1272w, https://substackcdn.com/image/fetch/$s_!50kN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!50kN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png" width="986" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:986,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!50kN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 424w, https://substackcdn.com/image/fetch/$s_!50kN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 848w, https://substackcdn.com/image/fetch/$s_!50kN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 1272w, https://substackcdn.com/image/fetch/$s_!50kN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd44e0c3c-53d0-438a-b75e-e624f1580016_986x464.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">GDPR sanctions by category over the years</figcaption></figure></div><p>What appears here is a rather balanced picture of different categories all being pursued more or less equally. The most obvious thing is that 2018 is <em>nothing</em> like other years, so I guess they had to start by finding their mark.</p><p>Something that seems to emerge as well is a stronger focus on the core company organization. Instead of just wondering if you violate people&#8217;s privacy, it is also important to look at how well structured your company is to ensure that the law is applied, whether you design your application to be private or you work properly with your third parties.</p><p>Now which of those measures should you be worried about?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7YzF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7YzF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 424w, https://substackcdn.com/image/fetch/$s_!7YzF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 848w, https://substackcdn.com/image/fetch/$s_!7YzF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 1272w, https://substackcdn.com/image/fetch/$s_!7YzF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7YzF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png" width="1456" height="1180" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1180,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7YzF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 424w, https://substackcdn.com/image/fetch/$s_!7YzF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 848w, https://substackcdn.com/image/fetch/$s_!7YzF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 1272w, https://substackcdn.com/image/fetch/$s_!7YzF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F14496224-6d77-4d1c-b68c-493a606e9eac_1460x1183.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Heat map of sanctions distribution by value and category</figcaption></figure></div><p>Obviously anyone can get hit anywhere and it is going to be hard to make a generic rule. But let&#8217;s look at some trends.</p><p>First let&#8217;s see about cookies and trackers. With so much noise surrounding them, are they so important? Turns out that, not so much. They definitely have been the platform used to battle the GAFAMs, but the smaller the company size and the least important it becomes.</p><p>Related to cookies, a line is emerging on consent. But it&#8217;s not <em>only</em> cookie consent. Rather, it&#8217;s the generic collection of consent for everything that should require it &#8212; from ads cookies to receiving commercial emails and everything in between. It is important to disconnect the concept of consent from the concept of cookies. The law never actually mentions cookies, it&#8217;s all about <em>what you do</em> with the data and how you justify it.</p><p>Talking of justification, this is clearly what emerges on the small red island in the 1k-100k range (web agencies and such). Things that hurt the most are not so much direct violations of the law but rather the lack of measures to apply and justify it. The message is clear, any company of any size should:</p><ul><li><p>Maintain a register of all PII data processing</p></li><li><p>Justify appropriately every single processing that is done<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p></li><li><p>Having a DPO in charge of guaranteeing that this work is done and able to talk with authorities</p></li></ul><p>While this is not what bigger companies seem to be lacking of, you can see that they are rather plagued by what is most likely legacy.</p><p>A first focus is to be made on security-minded topics. You can see recurring mentions of:</p><ul><li><p>Data minimization and expiration &#8212; limiting the attack surface to exactly what you need and no more</p></li><li><p>Data breach handling &#8212; you need to have proper security in place to avoid data breach, but you should also be transparent with your customers when their data gets leaked into the wild</p></li><li><p>Special categories of data &#8212; medical data for example requires a specific care, which is not always given</p></li></ul><p>And then comes in the straight-out malicious data processing:</p><ul><li><p>Improper commercial prospection</p></li><li><p>Lack of information and transparency</p></li><li><p>Refusal of user&#8217;s rights (portability, opt-out, etc)</p></li></ul><p>Let us also take note of something notably missing from the list of sanctions: not a single mention of using a hosting/cloud provider that is not EU-owned. Nobody got sued for using AWS, DigitalOcean or any other american hosting company. When you see that some of the sanctions are extremely specific, if this was on the map at all there would at least be a trace of it.</p><p>It is also worth mentioning that it doesn&#8217;t look like data processors got into any trouble. There are some examples of controller/processor relationships being sanctionned but it seems like most of the responsibility falls on the shoulders of the controller.</p><p>Overall, lots of categories are used few times and it is clear that the CNIL will target anything they can. But emerging patterns also come to show that a lot of focus is given not only on what you do but also how you do it. The main requirement of GDPR in the end is that you <em>care</em> about PII.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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>Conclusion</h2><p>Is GDPR hurting innovation? Should you be afraid of getting fined?</p><p>After initial years that were mostly focused on crucifying GAFAMs, it seems that the CNIL is getting a knack for smaller players as well. We don&#8217;t know yet how many sanctions will fall in 2024, but the rise in 2023 has been steep.</p><p>It is also becoming obvious that the infractions that companies will be sued for highly depend on the company size due to both the practices required to operate at this company scale and the tendency to invest or not in PII management. As such, here are the recommendations of what to change depending on your company size.</p><p><strong>Global companies</strong> &#8212; GAFAMs and other big players in web marketing</p><ul><li><p>Notch it down on World Domination</p></li></ul><p><strong>National companies</strong> &#8212; TV channels, telcos and other companies operating at a national level</p><ul><li><p>Assign a budget on sanitizing your data management. Eventually you will have to spend this money either as a GDPR fine, or as a hack ransom <em>then</em> as a GDPR fine. If you do it as an afterthought, the outcome will be a superficial fa&#231;ade falling at the first push.</p></li><li><p>The same goes for letting users exert their rights. It needs to be built-in into your tools and processes, otherwise it will not happen when you need it.</p></li><li><p>There are a bunch of forbidden commercial practices that you cannot be having anymore, indeed.</p></li></ul><p><strong>SMEs</strong> &#8212; Smaller local businesses, startups in initial stages, web agencies but also the local doctor for example</p><ul><li><p>Make sure to empower one person to be responsible for data management</p></li><li><p>Keep a register up-to-date with all PII processing and appropriate justifications</p></li></ul><p>So what of our question? Is GDPR hurting businesses? There is no denying that this regulation forces companies of all sizes to assign budgets on items that do not have a direct ROI, under the threat of a fine.</p><p>On the other hand, this serves to protect companies from themselves. The principles of data security for example are forcing down a much better hygiene which will over time save big houshold names from <a href="https://www.cshub.com/attacks/articles/incident-of-the-week-garmin-pays-10-million-to-ransomware-hackers-who-rendered-systems-useless">massive ransoms</a> and <a href="https://techwireasia.com/12/2023/how-has-toyota-suffered-so-many-data-breaches/">data breaches</a>. The industry still needs to gain a tremendous amount of maturity on the topic &#8212; this is but a push in the right direction.</p><p>The same goes with commercial opportunities. Have you seen the Mad Men episode <a href="https://www.youtube.com/watch?v=8SsnkXH2mQY">about Lucky Strike</a>? This is a similar situation. If you can&#8217;t do it, neither can your competitors. This is not the scope of this article, but you can imagine that the damage is not so great provided that everyone respects the law.</p><p>Which all leaves us with a mixed feeling. On one hand this is acting for the betterment of European society and has important positive externalities &#8212; a safer online experience for all of us. But it is only driven by the stick. Instead of giving huge tax credits for often bogus R&amp;D<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>, maybe a little help to the most vulnerable businesses could help them keep their books in order.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>GDPR allows you to use different categories of justifications for each data processing. You must fall within these justifications for every processing. One of them being &#8220;consent&#8221; but there are 5 others that might help you. See my <a href="https://dev.to/xowap/clarifying-gdpr-1gld">previous article</a> on the topic.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I&#8217;m talking here about the French &#8220;CIR&#8221;, which generates hundreds of millions for mostly the same GAFAMs that are being fined here and whose economic impact is <a href="https://www.alternatives-economiques.fr/isabelle-this-saint-jean/credit-impot-recherche-etre-reforme-durgence/00105294">quite controversial</a>.</p></div></div>]]></content:encoded></item><item><title><![CDATA[3 reasons why Webhooks suck and 2 Masterclasses to replace them]]></title><description><![CDATA[The most popular way for different services to send messages to each other should never have existed. We review why and how we can make it better, taking real-world implementations as examples.]]></description><link>https://www.baby-cto.com/p/3-reasons-why-webhooks-suck-and-2</link><guid isPermaLink="false">https://www.baby-cto.com/p/3-reasons-why-webhooks-suck-and-2</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sun, 28 Apr 2024 07:01:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0a8cac61-fbb0-4779-b34e-a93beea35e56_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The most common way for independent services to exchange messages &#8212; even more so on public APIs &#8212; are webhooks. A beauty of simplicity: you simply provide an URL that you want to notify when an event occurs and the other service simply has to make an HTTP call. Except, not really.</p><h1>Webhooks suck</h1><p>In the shadow of this superficial simplicity are creeping major problems which make it hard for both ends to exploit webhooks.</p><h2>Not missing a drop</h2><p>First of all, the most basic prerequisite for a webhook to work is that the receiving end is able to receive. Meaning that the webservice must be up and running. But what happens if a maintenance is ongoing, a technical issue plagued the server or simply the network connection has an instant of failure?</p><p>The message will simply and purely be lost. It&#8217;s a <a href="https://en.wikipedia.org/wiki/Byzantine_fault">Byzantine fault</a>: how can  you know if a message was sent if the sender is unable to contact you either way?</p><p>In order to remedy this, most providers resort to implementing retry mechanisms. Which is fairly complex to implement: you need to store somewhere that you&#8217;ll have in the future to execute a given set of messages and wake up accordingly. Most queuing systems will struggle at doing this reliably because they are working in &#8220;at least once&#8221; mode, meaning the same message could be sent twice. You can decide you don&#8217;t care but then your client has a problem on their side.</p><p>Another issue is that if you are doing a maintenance on your server, maybe you configured something wrong and it ends up responding 200 when actually the wrong service was receiving the message. In that case the message simply gets obliterated, given that the sender thinks it&#8217;s received and the receiver has no idea the message even exists.</p><h2>Avoiding flashbacks</h2><p>This retry logic will also amplify another danger. Messages could very well arrive out of order, and this for different reasons.</p><p>For example if you are implementing a retry mechanism but consider all messages as independent. In that case if the receiver gets unavailable for a while, they are at risk of receiving the missing messages after they started catching back with earlier messages. You can let the receiver with the burden of fixing this, but it honestly will get ignored most of the time.</p><p>What can happen as well is if your receiver operates at a larger scale and has at least 2 web servers, if two of your messages arrive at the same time and get processed by 2 different processes at the same time, there is no saying which message will be dealt with first.</p><h2>Harder to develop</h2><p>Now this is a more practical than theoretical consideration, but most of the time developers won&#8217;t have the luxury of a public IP address on their development machine. Which is a big problem since webhooks are actually going to have to initiate the network connection, meaning that you will probably end up resorting to tools like HTTP tunnels.</p><p>On top of that it means that your code needs to be aware of its own public URL, which you cannot really do automatically. For example if you use a regular API,  you never need to declare what is your public address. But for webhooks you need to know what it is and to declare it. Often through complex back-offices or needing propagation times.</p><p>As a result you end up with an extra configuration variable which you could probably avoid otherwise, you probably also need to go through some manual configuration and on top of that free plans of popular HTTP tunnels will change your URL every time so you possibly end up changing it all the time.</p><h1>There are alternatives</h1><p>How do we deal with this situation better than with webhooks? First you need to realize that you are actually trying to solve two separate problems:</p><ol><li><p>Knowing that there is at least one update pending &#8212; when an event occurs then your code needs to wake up and do its job, preferably as fast as possible after said event.</p></li><li><p>Synchronizing state &#8212; the final goal of this is to have different systems converge into the same state, whether it&#8217;s knowing if the user expects the light on or to get the full status of a shared online document.</p></li></ol><h2>Waking up remote code</h2><p>The most naive thing you can come up with is polling. Every X seconds you&#8217;ll check if there are updates available. This is however considered as wildly inefficient:</p><ul><li><p>The cost of establishing a connection is pretty high relatively to other options.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p></li><li><p>You won&#8217;t get the updates &#8220;in real time&#8221; but rather only every time you poll</p></li></ul><p>That&#8217;s why in most cases, polling will not be recommended and both software and hardware architecture were designed to avoid polling. If you were to simplify it to the extreme, modern computers are driven by inputs. A physical electrical signal on your network card will trigger a processing chain that will eventually wake up the relevant process, all the way down to your favorite abstraction from Python, JS or any other language.</p><p>This is what makes webhooks attractive: a remote computer can wake up your local process. But it&#8217;s not the only way to do it. If you open a network connection from your local machine to the remote API &#8212; which is extremely easy to do even without a public IP address &#8212; then as long as the connection is up then packets will be flowing both ways.</p><p>WebSockets were invented exactly for this. It&#8217;s an easy way to have a client, typically behind a NAT or a proxy, to connect to a server and receive real-time updates. That would be my go-to option for waking up remote code.</p><p>Alternatively, before WebSockets we used a technique called &#8220;long polling&#8221;. The idea is to make a regular HTTP query but that hangs for a very long time (typically minutes) until an update happens and the HTTP query returns with the message. A bit messy but almost as efficient as WebSockets if you don&#8217;t have a very high throughput and not more costly than webhooks.</p><p>When implementing this kind of technique, you need to consider that you will be maintaining one full TCP connection with every single client. That used to be a challenge, it is becoming quite easy these days if you can use an async infrastructure.</p><p>Alternatively you can turn towards dedicated services like <a href="https://cloud.google.com/pubsub?hl=en">Google&#8217;s Pub/Sub</a>, <a href="https://aws.amazon.com/eventbridge/">AWS EventBridge</a> or countless others. For example, Shopify offers webhooks but recommends notifications through <a href="https://shopify.dev/docs/apps/webhooks/configuration/eventbridge">AWS</a> and <a href="https://shopify.dev/docs/apps/webhooks/configuration/google-cloud">Google</a>. Kind of the same as dealing with the WebSocket yourself but you let someone else manage the scale for you.</p><h2>Staying on the same page</h2><p>Distributed systems are notoriously hard and I am not aware of an universal law that allows you to deal with any situation whatsoever, especially as you scale up. However it usually boils down to the same core idea &#8212; which can be remixed at will to fit the project&#8217;s needs.</p><p>Consider that your data model is a bit like a Git repository. At a point in time, the source code has a given state but in order to reach there a series of different edits had to happen. Said otherwise, if you sum up all the edits then you get the state of the code at a point in time.</p><p>So the key here will be to identify which edits happen in your model, convert them into a stream of events and re-compose them on the other side. This can be more or less difficult to achieve, for example Google Wave used <a href="https://en.wikipedia.org/wiki/Operational_transformation">Operational Transformation</a> which took 2 years to develop but on the other hand if you&#8217;re just dealing with a messaging app your life should be much simpler.</p><p>Now imagine all those edits as a sequential log. As you read the log, you keep track of your current cursor, pointing to the latest known edit. When you are notified of another event then you need to read starting from this cursor.</p><p>This resolves a lot of issues raised earlier:</p><ul><li><p>By using edit logs, your communication protocol is basically writing itself and will look fairly simple. If you&#8217;re used to Vuex or Redux, it&#8217;s basically the idea behind mutations.</p></li><li><p>The cursor allows to know where we are in the update stream. If you lost a notification because your program was down or crashed, you can catch back from your latest known state.</p></li><li><p>Even if the transmission of messages fails, you can easily have a retry mechanism to eventually get up-to-date.</p></li><li><p>There is no risk from getting the same message twice as messages are basically sequential, numbered items.</p></li></ul><p>From looking at WhatsApp&#8217;s WebSocket communications, you can presume for example that they use this kind of strategy and it&#8217;s even what enables them to have end-to-end encryption with consistent shared states between participants and devices while having servers completely oblivious to the actual content of conversations.</p><h1>Masterclasses</h1><p>Having recently interacted with different APIs, two of them really stand out in my opinion, showing how you can make a public API that avoids pitfalls explained earlier. I picked them up because the choices they made really highlight how you can implement things in correct way while also keeping things simple.</p><h2>Telegram</h2><p>The world of instant messaging is highly competitive, with all major players pushing their platform as hard as they can. Facebook has the two most popular platforms &#8212; WhatsApp and Messenger &#8212; however the third one is a pure player gaining traction only through their strategy<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><p>One part of this strategy is to have an amazing bot experience, allowing with very small developer effort to create real-time applications. This is particularly prominent in the cryptocurrency world but for example it&#8217;s also a tool heavily used in Ukraine to follow bombing threats.</p><p>The basic idea of Telegram is pretty simple. You have different conversations in which you come add messages. Then more complex things can happen like people putting reactions, messages being edited, user clicking buttons, etc. All of them are listed and <a href="https://core.telegram.org/bots/api#update">documented updates</a>.</p><p>Now the interesting part. How do you get those updates?</p><p>A first method is the webhook. As you know, it sucks. The more interesting method is the long polling <a href="https://core.telegram.org/bots/api#getupdates">getUpdates</a> method. It combines two techniques explained earlier.</p><ul><li><p>Long polling &#8212; the HTTP call will hang until either an update or a timeout happens. Not as efficient as WebSockets but very easy to implement because you can do it with literally any HTTP client ever written. And of course it works from a private IP address.</p></li><li><p>Cursor &#8212; the call takes an <code>offset</code> argument, which corresponds to the ID of the last message you received.</p><ul><li><p>This is a smart way to get you to acknowledge receiving the previous messages and receiving new updates in one single call.</p></li><li><p>But on the other hand if you pass an offset of 0 then it will repeat the last offset that used. This means that if you restart your app you don&#8217;t need to remember the last offset, which is incredibly convenient.</p></li></ul></li></ul><p>As a result, developing a client for the Telegram Bot API is a very smooth and simple experience. All you need is a HTTP client and a tiny wrapper around it to get started. You can use a lib of course but implementing a client from scratch is a very easy task both in terms of code (no need for crazy libs) and of infrastructure (almost no constraints).</p><h2>Plaid</h2><p>If you never heard about <a href="https://en.wikipedia.org/wiki/Open_banking">Open Banking</a>, it&#8217;s basically all the banks in the world somewhat converging into providing standardized and modern APIs for all their services. At least in theory, in practice of course the capabilities and implementation details vary greatly country-to-country and instead of a truly open standard you need to go through middlemen such as <a href="https://plaid.com/">Plaid</a>. This is not my field of expertise so I can&#8217;t go into the details but all I can say is that Plaid does a great job at converting <s>dinosaurs</s> banks into REST APIs.</p><p>They have a wide number of APIs but the one that I&#8217;m interested into is the Transactions API. The most interesting information about bank accounts, especially if you are building a personal finance app, is to see the list of transactions that happened there.</p><p>One of three thing can happen, with examples:</p><ul><li><p>A new transaction happened (you bought something)</p></li><li><p>A transaction got modified (exchange rate got finalized)</p></li><li><p>Or it can be deleted (transaction was not captured in the end)</p></li></ul><p>In the case of Plaid, they work a lot with batches. I don&#8217;t even want to know how they receive those transaction but if you told me they came from a latin-1-encoded CSV file dropped on a FTP every 3h I would not be surprised. As a result it&#8217;s much less <em>real-time-ish</em> than Telegram. It&#8217;s not extremely relevant to ship every event individually.</p><p>Instead they&#8217;ll give you a cursor &#8212; up to you to keep track of it in that case &#8212; and give you <a href="https://plaid.com/docs/api/products/transactions/#transactionssync">aggregated added/modified/removed transactions</a>. Which makes it very easy to update your own database. If you just had the list of latest transactions for example, you&#8217;d have to diff the DB to know what to create, update or delete. But here you can blindly do a bulk insert, bulk update and delete. 3 SQL queries maximum and done.</p><p>The only issue I have with their system is that&#8230; It&#8217;s based on webhooks &#128531;</p><p>But that&#8217;s not causing much harm. Of course it means you need to setup a HTTP tunnel before developing with their API but on the other hand because they have this sync method you avoid all the other drawbacks pretty easily. You can even poll the API every day if you don&#8217;t care about being &#8220;as fast as possible&#8221;.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reaching the end! Give it a subscribe if you feel like learning more on architecturing your code and your company.</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>Take away</h1><p>Webhooks suck because they bring a hoard of subtle yet annoying problems. Most queue systems are either &#8220;at most once&#8221; or &#8220;at least once&#8221;. Webhooks are &#8220;probably once &#129310;&#127995;&#8221; and bring with them a terrible developer experience.</p><p>But what we really need to do is decouple two problems: the one of waking up remote code and the one of synchronizing state.</p><p>Waking up remote code is fairly easy now that async architectures are widespread, you can either rely on an external cloud provider or simply let people open websockets to you.</p><p>And then regarding state synchronization, most likely you want a somewhat linear sequence of events to be streamed to your consumer, relying heavily on the concept of cursors to let remote code communicate its current knowledge of the state.</p><p>At the end of the day, if you are making a public API, the developer experience is going to matter a lot and involves in the current case two main elements:</p><ul><li><p>How complicated is the code going to be when using your API? The lightest the required wrapping, the least the data post-processing, the better.</p></li><li><p>How hard will the problems be to solve in terms of infrastructure? States to be kept, network flows, etc. Keep in mind that most apps start from scratch so optimize for small operations rather than world-scale conglomerates.</p></li></ul><p>So if you are making a public API &#8212; for the wide web to use or simply for other parts of your company &#8212; please think well how you can make the life of your peers easier and safer!</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>It&#8217;s not <em>that</em> high, I still do a lot of polling when I&#8217;m short in time and it will make almost no difference on the result.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Not making any judgement or recommendation here. You can be pretty sure that half the secret services in the world read your Telegram messages, but it <em>is</em> a massive platform on which you can build many interesting things.</p></div></div>]]></content:encoded></item><item><title><![CDATA[5 criterion to pick your front-end framework]]></title><description><![CDATA[Where we take an objective look at all options ranging from jQuery to Remix in order to figure which should you use for your next front-end project.]]></description><link>https://www.baby-cto.com/p/5-criterion-to-pick-your-front-end</link><guid isPermaLink="false">https://www.baby-cto.com/p/5-criterion-to-pick-your-front-end</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sun, 14 Apr 2024 07:01:31 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d7d07a89-96c8-4658-8357-1feb927dc8e5_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One thing for which yours truly is particularly glad is to have been able to partake to the development of the Web for two thirds of its history and to see all the twists and turns it has taken over the year. Now that the big platforms dominate it, that Chromium has a quasi-monopoly &#8212; except for Safari, which is a lesser version of the same thing &#8212; and that the hoops to jump are just so numerous, one can only imagine that getting into web development must be a disheartening thing.</p><p>Let us however keep an eye on the North. Imagine you were to create a major project right now, which involves a website, what route should you wish to take?</p><ul><li><p>The old school would go towards <a href="https://jquery.com/">jQuery</a></p></li><li><p>The minimalists would pick <a href="https://htmx.org/">htmx</a></p></li><li><p>And the mainstream would pick a meta-framework such as <a href="https://remix.run/">Remix</a>, <a href="https://nuxt.com/">Nuxt</a> or <a href="https://kit.svelte.dev/">SvelteKit</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p></li></ul><p>Those three voices will often be vocally contradicting each other on social media, adding confusion into the mix. Of course there are no silver bullets, only bullets that will hit the target more difficultly than others. My bullet is the meta-framework, and that&#8217;s not out of kool-aid nor fear.</p><p>For the first years of my career it was impossible for me to use meta-frameworks, for they were not invented yet. This was a painful experience. If you end up creating a real-time interactive game in which the whole DOM is dynamic, trust me jQuery is <em>definitely not</em> the tool for the job.</p><p>On the other hand if you are not creating something so deeply interactive, chances are that jQuery &#8212; a library whose main purpose is to even out the differences between Internet Explorer 6 and Firefox 2 &#8212; isn&#8217;t going to be <a href="https://youmightnotneedjquery.com/">of great help</a>. Especially if you are feeling more like a backend person, a tool like htmx will allow basic interactions which require very little front-end work and might just be enough for you.</p><p>But if you work for projects of a more unpredictable nature then maybe those solutions are not optimal. It&#8217;s with the mind set on a large, enterprise-grade&#169; project that we&#8217;ll go in quest of the perfect framework to build your startup.</p><h2>Performance</h2><p>A common consideration against meta-frameworks will be the performance. Surely, all those features must come at the cost of very expensive and bloated JavaScript runtimes? Let&#8217;s put that to the test. I&#8217;ll make a hello world page using major frameworks and measure the transfered payload size (gzipped for the most part):</p><ul><li><p>HTMX &#8212; 16 kio</p></li><li><p>SvelteKit &#8212; 25 kio</p></li><li><p>jQuery &#8212; 30 kio</p></li><li><p>Remix &#8212; 90 kio</p></li><li><p>Nuxt 3 &#8212; 131 kio</p></li></ul><p>This tells us that meta-framework do not have to be heavy and clunky. They can, like Remix and Nuxt 3, but SvelteKit is lighter than jQuery in that regard.</p><p>What about the execution speed, memory use? <a href="https://krausest.github.io/js-framework-benchmark/current.html">This benchmark</a> is fairly popular and while it doesn&#8217;t include HTMX nor jQuery, it does have vanilla JS, which should be the closest to what you can achieve. You&#8217;ll have to explore the numbers yourself but in a nutshell even React that is often lagging behind stays pretty close to the baseline. The same goes for memory use.</p><p>In any case, those benchmarks are toys. The better question is: how fast is your website going to be at scale?</p><p>The clear winner is going to be HTMX, because all the rendering logic happens on the server, which isn&#8217;t so much bound by script size. On the other hand, all the other options will have to write numerous lines of code. If you write your project using jQuery, you will be ending up either with one big JS file, either with a collection of different files but either way, the organization will be yours. Now if you want to minify all this, you will not escape the need for a set of build tools. When scaling up, it <em>is</em> difficult to escape having a build stage.</p><p>And while meta-frameworks also have a build stage, this process is entirely integrated. You don&#8217;t have to do anything: your code gets transpiled, minified and processed in all the necessary ways completely automatically. With the added bonus that the build tools are aware of the dependency tree. As a result, every page can automatically be bundled in its own file, so that you never need to load code that you don&#8217;t need immediately.</p><p>From the performance standpoint, you thus have two choices:</p><ul><li><p>Either you think that HTMX will never be a limit in what you are trying to achieve, in which case it is the easiest option</p></li><li><p>Or you need to have some wiggle room in terms of feature &#8212; 100% of my professional projects &#8212; and then a meta framework will be a far superior option for a relatively small price to pay</p></li></ul><p>Let&#8217;s declare the winner of this round: SvelteKit!</p><h2>Maintainability</h2><p>While a strong argument of the web development community was the separation of concerns between HTML and CSS, you need to understand that at this time people were writing CSS directly in the style tag, making poor use of semantic and limiting greatly reusability. It is however essential to consider <a href="https://www.baby-cto.com/p/html-the-facade-of-complexity">HTML, CSS and JS as a whole</a>.</p><p>This is why the concept of <em>component</em> is everywhere. It&#8217;s the same as the widgets from UI frameworks. The advantage of a component is that, like explained above, it has a clear dependency tree, it contains all the code that is required for its proper execution and if you want to refactor or delete it you do not need to look for its bits and pieces all over your code base, worrying about side effects.</p><p>The first and most important question to deal with is the CSS, whose C stands for &#8220;Cascading&#8221;. It&#8217;s another way to say &#8220;if you are not careful, one change here will cascade into disfiguring your whole product&#8221;. You could deal with the styling of your component by writing the style into the style tag directly, or even generate all the possible styles into classnames and write the style into the class tag directly. But that is exactly what the Elders warned us about.</p><p>A more interesting approach is to define the <a href="https://cssinjs.org/">CSS in JS</a>, which allows you two things: first the CSS gets bundled with your JS &#8212; and your HTML de facto &#8212; and second it gets a scope wich will not overal with the one of other components. It&#8217;s just a shame to be doing this manually and to deprive yourself from tools like SCSS, which make writing CSS much easier. That&#8217;s what Single File Components (SFCs) allow and they are available in both Vue and Svelte but weirdly not in React.</p><p>Once you have scoped and bundled together your CSS, JS and HTML generation then it becomes hard to write spaghetti code. Knowing that on top of that the build system will track all your dependencies, as said earlier, this allows for an extremely atomic compilation and optimization process.</p><p>On the other hand, when using jQuery or HTMX, you will be left to your own devices. Not necessarily a bad thing but the organization becomes up to you. As soon as two developers start working on the same code base, we know that t he organization can quickly go through the window.</p><p>Henceforth, we got here two winners for scalability and team work, which are SvelteKit and Nuxt 3.</p><h2>Future-proofness</h2><p>If you create a startup which depends heavily on a given framework in order to work, you want to make sure that after you have invested five years of developer time you don&#8217;t end up having to rewrite everything from scratch. Those tools need to give a good perspective to developers. For example, you can still run on a Windows machine an unmodified DOS program that was written in the 80s. Without being so extreme, if you cannot see at least 10 years forward with a tool then you have a problem.</p><p>First of all, let&#8217;s look at jQuery. Almost 20 years later the API is still basically exactly the same, version upgrades being mostly about simplifying the code because browsers are converging now. If that&#8217;s the route you intend to take the rest assured that jQuery will not go anywhere.</p><p>Then HTMX. Honestly it&#8217;s hard to say anything at this point. Small project, the maintainer probably can&#8217;t promise anything. Chances are it will only add features through time but due to its nature I can&#8217;t imagine how they could introduce major breaking changes. The main risk is more that the project dies, but even then it probably wouldn&#8217;t be too hard to maintain it yourself it it came to that.</p><p>On the React side, I don&#8217;t practice it often enough to go in-depth into it but in any case the ecosystem is so vast that you could probably write another article dedicated to chosing the right React stack. In that regard, it seems like breaking changes do occur in every part of the ecosystem but overall it&#8217;s never going to be something fundamental that asks you to through your entire codebase in the trash.</p><p>Which is fairly different from what you could say about the Vue ecosystem. Vue 3 has been a major breaking release and introduced a whole new set of completely different APIs (the &#8220;Composition API&#8221;) and while it is not inherently bad it changes completely the way to think about your code. In theory you don&#8217;t have to use it but every single library of the ecosystem only supports this anymore, so you don&#8217;t actually have a choice.</p><p>Including the Vue-3-compatible version of your favorite libraries/tools (if ported), which will force you to rewrite everything that depends on it. The main one being Nuxt 3, which came out with exactly zero overlap in API or conventions. There is <em>nothing</em> that works the same anymore and the thin compatiblity layers that exist usually are fickle, fragile and generally useless. This feels like a serious backstab barely 6 years after version 1 &#8212; yes I have products that would cost 6 figures to upgrade and I&#8217;m pissed about it.</p><p>Now remains to evaluate Svelte&#8217;s position. While I can&#8217;t find any official statement on where Svelte will be in 10 years, some good indicators are there. Firstly, the documentation is written in a way more practical way than others, showing that they care more about the use cases than the technicality of the framework. Secondly, so far upgrades have been relatively smooth. And finally Svelte 5 is cooking and the ugprade process also seems clear. Now since the ecosystem is much smaller, it&#8217;s hard to tell what is really going to be the impact, but let&#8217;s keep our eyes open.</p><p>Overall, the only tool that has demonstrated a serious commitment towards backward compatibility is jQuery, which will have to be winner of this round!</p><h2>Cognitive load</h2><p>You have probably one day heard of GTD and decided to try it for yourself. One of the advice coming out of it is: if it takes less than 5 minutes, do it immediately. So tell me, how many days did you end up spending 100% on 5 minutes tasks? Did it feel satisfying? And did you accomplish anything meaningful?</p><p>Of course it&#8217;s a rethorical question and you can&#8217;t really answer so you&#8217;ll have to imagine that you said &#8220;it&#8217;s satisfying but not meaningful at all&#8221;. Which is what happens as well with many tools that we use and that we might judge on the satisfaction to use them while actually we lose our time doing boilerplate.</p><p>Imagine that you are writing an interactive component which depending on the user actions and inputs will have to update its own DOM. Doing it in jQuery can be extremely satisfying because you create all the elements yourself, find smart ways to hook events, imagine optimizations to do it faster, etc. Very fun if it&#8217;s your jam. But on the other hand if you do the same thing with Svelte, the compiler does all this automatically and better than you ever would. Managing the DOM is just not a task with Svelte.</p><p>So while it&#8217;s satisfying you just spent your time on something that should not even grab your attention. What about our contenders?</p><ul><li><p>jQuery &#8212; As mentioned above, it&#8217;s all manual from the manipulation of the DOM to bundling it to the client. Easy to marvel at the beauty of your code, hard to actually focus on what matters.</p></li><li><p>Remix/React &#8212; Many moving parts and optional APIs (hooks, signals, etc). No management of CSS. Fairly complex overall.</p></li><li><p>Nuxt/Vue &#8212; Version 3 of both definitely made things more complex, with two competing APIs (including a fairly verbose one) and lots of build-time magic.</p></li><li><p>HTMX &#8212; Very lightweight front-end but on the other hand you still need to worry about the back-end yourself, so it&#8217;s a lot of unknowns</p></li><li><p>Svelte(Kit) &#8212; Once you&#8217;ve sorted out the idioms, it is fairly straightforward and requires no magic of any kind</p></li></ul><p>Hence, I&#8217;ll give the round to SvelteKit!</p><h2>Community and talent pool</h2><p>You could find the best framework of all times, if nobody can provide for you libraries that solve common problems (UI libraries, form validation, toasts, etc), learning resources or direct support then you are going to have a hard time.</p><p>On top of this, you need to be able to hire developers. A decent developer can learn any decent framework but they need to <em>want</em> to work with it and usually they&#8217;ll expect that it&#8217;s going to look good on their CV.</p><p>The same goes commercially speaking. Lots of customers are interested in knowing what tools you use and if you can&#8217;t justify that it&#8217;s durable and bullet-proof they might get cold feet when deciding to work with you.</p><p>So here is what to expect:</p><ul><li><p>jQuery isn&#8217;t sexy anymore, nobody needs it on their CV, nobody wants to work with it except a few indiepreneurs that claim jQuery pays for their lambo. Customers who look into your tech stack will ask you if jQuery is a headless framework and it&#8217;ll be hard to say yes.</p></li><li><p>HTMX is straight away a no go. It&#8217;s too small to put on a CV and not trusted enough to fuel a sales pitch. Using it in a professional setup right now will require a serious offset on other parts of your stack.</p></li><li><p>React is a no-brainer. Everyone wants it on their CV, it&#8217;s backed by a major player and the community is one of the largest for a framework of that kind. Plus, most companies that publish SDKs or component libraries will prioritize React.</p></li><li><p>Vue is the new React, except less popular, less demanded and less clunky. Still a workable option.</p></li><li><p>Svelte is on the line. But it receives a lot of developer love (like HTMX you&#8217;ll tell me) and is now backed by Vercel which not as big as Facebook but definitely big enough to make this serious. Plus Svelte 5 is promised to resolve all pending Svelte issues, which should boost adoption.</p></li></ul><p>Basically I have to give this round to React (hey at least one).</p><h2>Conclusion</h2><p>There are a million of other items to consider and of course many more frameworks than those. But in my experience those themes are the most important to consider when picking a technological stack.</p><p>So which framework should you use?</p><p>In the absolute, go with SvelteKit. Provided that the version 5 of Svelte doesn&#8217;t turn out to be a major betrayal of the community. It&#8217;s lightweight enough, scales well with teams, focuses developers on what matters and should not ask you to rewrite your whole application in 2 years &#8212; especially if you waited for version 5.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>Yes you will get more difficulties finding talents for it but on the other hand it has good press and you can learn the bulk of it in a few hours. There are of course a few rough edges but nothing insurmountable. Same for your sales pitch, you can always make diversion by using a hot headless CMS.</p><p>Another interesting option if you were building your own startup with a Craigslist-type UI would be to use HTMX. Besides the talent pool, the main thing about using HTMX is that developers need to have the final word on UX/UI, because otherwise you will be fighting against the framework all the time. But if you can keep it constrained, you&#8217;re probably going to have a very efficient experience.</p><p>Now regarding other meta-frameworks, we see that they all come with dealbreaking drawbacks &#8212; namely React being a huge spaghetti bowl and Vue being a traitor. Not that you can go particularly wrong with them, but it&#8217;s just not good choices in my opinion. If you are really afraid about what others might think you can always pick some assembly of React things, but be warned that it comes at a cost for your mental load and the one of your browser.</p><p>Finally if you are team jQuery, of course it&#8217;s a safe and proven choice which will continue to support you for the next 100 years I&#8217;m certain. Which is more than you could say about anything else on that list. It&#8217;s probably good if your app is small and you have few resources to invest in the front-end.</p><p>So while there are indeed no silver bullets, it&#8217;s important to outline that given the current state of the art you are much safer and much better off with a meta-framework, especially if it&#8217;s SvelteKit. Other options exist and can be valid for some use cases but as someone that oversees the production of many front-end applications I can only recommend to stick with a paradigm that covers all angles at minimum cost.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>If you&#8217;re wondering why Angular is not part of this comparison while it definitely has the credibility to fit in there the answer is twofold. First of all, they invented backstabbing in the JS framework world. And since they backstabbed me, I didn&#8217;t get any experience with it so it would be very hard for me to talk about it. All I know is that it has no chances of winning according to the evaluation below.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>If Svelte 5 <em>also</em> ends up in treason, then I&#8217;m not sure what advice to give. If treason is acceptable then Vue is a superior option due to its large popularity while avoiding many of React&#8217;s pitfalls.</p></div></div>]]></content:encoded></item><item><title><![CDATA[The inevitability of Magic Quidditch: when Mixed Reality meets muggle sports]]></title><description><![CDATA[Exploring the convergence of spatial computing technologies and how the challenges left to bring Magic Quidditch into existence]]></description><link>https://www.baby-cto.com/p/the-inevitability-of-magic-quidditch</link><guid isPermaLink="false">https://www.baby-cto.com/p/the-inevitability-of-magic-quidditch</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Mon, 08 Apr 2024 07:01:42 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e34d4310-cc79-4c76-986c-ec7cd29508dc_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When 11-years-old me received for Christmas my first Harry Potter book &#8212; and in spite of my utter lack of interest for team sports &#8212; it didn&#8217;t take long before I started drawing up ideas for a Quidditch simulator, with a 360&#176; screen, blue/red glasses and a mechanical arm to slam a ball in your face. After concluding that I didn&#8217;t have the skills nor the funding to start such an endeavour I let the project on my shelves and moved on forever&#8230; or so did I think?</p><p>&#8220;Recently&#8221; &#8212; 2016, be the judge of that &#8212; I was jogging around the Parc de Vincenne in Paris and to my surprise was seeing multiple teams practicing a sport that didn&#8217;t quite look like anything I knew and even less that I would imagine gathering crowds. Turns out that there is a real-life <a href="https://en.wikipedia.org/wiki/Quidditch_(real-life_sport)">muggle quidditch</a> (apparently quadball now, copyright yay) that has rules and that can physically being played. And that you don&#8217;t win just by catching the Golden Snitch apparently, sorry Harry.</p><p>Which leaves us on one hand with a sport that is surprisingly well-structured &#8212; with a <a href="https://iqasport.org/events/world-cup">world cup</a>, leagues in every country and more than 10,000 players if you believe the numbers &#8212; and on the other hand with the Mixed Rea&#8230; Spatial Computing finally emerging to a usable point. Is it time to bring a little bit of magic to this world?</p><h2>The map</h2><blockquote><p>For those who don&#8217;t know Wardley Maps, it is an analysis framework based on military strategy and applied to business. There is a long boring book of 700 pages (or a 15h-long audiobook if you prefer) to explain it in details with hard, scientifically-studied mechanics and rules. There are <a href="https://learnwardleymapping.com/">simpler resources</a> to get into it, which I definitely recommend.</p><p>In essence, it allows you to place on a 2D map business concepts and to know how they are going to interact with each other. This allows you to predict what is going to happen and when it&#8217;s going to happen with much more precision than reading tea leaves or hiring consultants.</p></blockquote><p>Let&#8217;s go back to our current topic. Here is the map of Magic Quidditch, if you want to watch it from a stadium near you.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VK0h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VK0h!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 424w, https://substackcdn.com/image/fetch/$s_!VK0h!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 848w, https://substackcdn.com/image/fetch/$s_!VK0h!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 1272w, https://substackcdn.com/image/fetch/$s_!VK0h!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VK0h!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png" width="1200" height="848.0769230769231" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:1029,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:277994,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VK0h!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 424w, https://substackcdn.com/image/fetch/$s_!VK0h!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 848w, https://substackcdn.com/image/fetch/$s_!VK0h!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 1272w, https://substackcdn.com/image/fetch/$s_!VK0h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa270f495-9e6c-47fe-8a4a-fc799a33d0aa_2691x1901.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Wardley Map of the Magic Quidditch</figcaption></figure></div><p>The map allows to clearly see dependencies in space and one of its most practical properties is to help you decide whether you build, buy or outsource something. By looking at the connected and close-up sections of this map, we can decide to group different parts and how we can approach them.</p><ul><li><p><strong>Make Yourself</strong> &#8212; As a magic provider, this is what you will want to develop yourself</p></li><li><p><strong>Partner Up</strong> &#8212; A section of utmost importance in your value chain but that you can&#8217;t possibly make from the ground up yourself</p></li><li><p><strong>Leave it to Apple</strong> &#8212; Apple and other big actors are already pushing this section hard enough so you don&#8217;t need to worry about it</p></li><li><p><strong>Muggle Quidditch</strong> &#8212; There is already a vast community of quadballers, players and spectators. While it&#8217;s proving interesd, it&#8217;s also going to be a challenge to onboard them</p></li></ul><p>So how do we get started?</p><h2>Leave it to Apple</h2><p>What has been abundantly obvious to me since swarms of people were chasing Pikachus in all the streets over the world during the summer of 2016 is that <em>reality</em> is about to become a much more flexible concept. If bars were paying to lure Pok&#233;mons &#8212; and the trainers that sought them &#8212; how are those creatures not real? It was involving real money with real people and real consequences.</p><p>There has since been a large number of devices and detours, from the Google Cardboard to the Metaverse madness going through by the Magic Leap and countless other attempts. All of them failed to produce a convincing experience until the Apple Vision Pro came around a few weeks ago. It&#8217;s just an increment on top  of it all, but definitely crosses a threshold.</p><p>It is however lacking one thing. Niantic &#8212; the maker of Pokemon Go &#8212; understands that what makes reality real is that it can be shared between people. And while they released their framework Lightship which runs on several devices, it&#8217;s still not available on the Vision Pro. Which in turn is really focused on the hardware and not so much on its applications.</p><p>To summarize, while we&#8217;re not exactly there yet, the convergence is painfully close:</p><ul><li><p>Digital worlds can be overlayed to the physical reality and shared between different people in real time</p></li><li><p>All the subtleties like eye tracking, mobile compute power, energy supply, etc are solved at an acceptable level today</p></li><li><p>Devices are increasingly able to merge physical and virtual, with different techniques and qualities</p></li></ul><p>While we still need to see all of that in a single affordable device, one can project this to happen in a matter of years of not months. As a reminder the Apple 1 was released for $666.66, which is about the price of a Vision Pro adjusted for today&#8217;s dollar.</p><p>Knowing this, we know one thing for certain. This will enable a whole range of applications which were not previously possible and open a completely new industry. And when you know how much stadiums and entertainment parks cost, it&#8217;s not unthinkable to imagine them as the first clients for &#8220;Spatial Computers&#8221;.</p><h2>Muggle Quidditch</h2><p>In the Harry Potter lore, <em>muggle</em> means <em>non-magic</em>. Given that we are indeed forbidden the world of wizzards, thousands of people joined hands in nonetheless adapting Quidditch to our lowly muggle world.  And as explained in introduction, you will find them training and competing in various locations all around the globe.</p><p>The fact that an entire generation &#8212; my generation &#8212; decided to simply ignore the limitations of the physical world because they would much rather live in a magic universe is simply incredible to me. There are a lot more of us nerds out there than I previously thought!</p><p>Which turns out to be a great news for any purveyor of magic &#8212; or the next best thing, Mixed Reality. And when magic becomes real, what better candidate than the most famous magical sport?</p><p>The existing base of leagues, players and public is an incredible starting point for such an endeavor. It&#8217;s not like if you pulled a new sport ex nihilo: we know that it exists, with the potential to be pushed much further.</p><p>The issue is that if you want to make Magic Quidditch you&#8217;ll need to be very careful how you approach this. The spark that ignited those players came from the Harry Potter lore but what feeds their fire today is the sport as it is. As such, an absolutely crucial aspect to Magic Quidditch will be to change how spectators perceive the sport without changing one bit how it is played today.</p><p>Beyond this if you were to pour a lot of money into a sport that is entirely amateur today it would probably become divisive for the community, create tensions that don&#8217;t exist today, progressively replace the profile of players, etc. I&#8217;m not an expert in sports but given the corrosive power of money you can expect something will get lost on the way. Does Quadball deserve such a frustrating makeover? The exercice is left to the reader, but what is for sure is that you will need to gain the adhesion of the community before anything else.</p><h2>Partner up</h2><p>Since we don&#8217;t want to change how the sport is played, how are we going to inject magic in it?</p><p>We&#8217;ve talked about the downside of money, but it also comes with a lot of upsides. Including in the present case, all professional sports have been saturated with analysis technologies which can tell you everything going on in the field in real-time. For example <a href="https://www.hawkeyeinnovations.com/insight">Hawk-Eye</a> will give you stick figures of all the players, exact position of balls in relation to delimitations, etc. It could probably do all the referee&#8217;s job automatically.</p><p>So here&#8217;s a dillema. On one hand nobody has Quadball tracking, on the other hand those people are a few million dollars closer to it than you are. The most logical thing here would be to partner up. Pay them to do the Quadball version of their software and then simply use it.</p><h2>Make it yourself</h2><p>At this point we are outsourcing the magic, the public, the players and the tracking of them. So what is left for us to do?</p><p>The idea for a match is simple. You gather everyone in a stadium, you put the players on the grass and you let them play as they would usually play. Then a tracking system gets all their motions, translates it into 3D and the public sees digital avatar of players flying on their broomsticks over the field.</p><p>Two obvious components emerge from this:</p><ul><li><p>The &#8220;tracking to magic mapping&#8221;. You&#8217;ll need to figure an engine that understands the game from what the tracking system reports and converts it into a scene with wizzards flying all over the stadium, in three dimensions (versus basically two in a Quadball game).</p></li><li><p>And of course the rendering of that scene. Which will have to run in the headsets directly so that everyone can see it from their own perspective.</p></li></ul><p>Given the quality of render and actual gameplay of games like FIFA/PES and friends, while this certainly is going to require a lot of work, this seems to be an expensive but safe challenge.</p><p>There is however another item that requires attention, which is the connectivity. Indeed, streaming this to a stadium at full capacity is a technological challenge that is yet to be seen accomplished. So many clients would completely tear down a WiFi network and 5G deployments are actually identical to 4G in most cases. Theoretically speaking however, you could do it with either properly configured 5G &#8212; which remains to be seen outside a lab &#8212; or with a finely tuned WiFi and strictly multicast data streams.</p><p>In short, there is a certain amount of cash to burn in order to even reach the first decent demo &#8212; with pratical challenges such as the massive connectivity required &#8212; but this seems quite achievable.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading thus far! If you liked my ideas, many more will be published. Don&#8217;t miss out the next editions!</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>Conclusion</h2><p>Quidditch is a long-term dream of a whole generation, which manifests itself by the fact that people are actually playing it today. On the other hand, when you see that billions are being poured into Mixed Reality/Spatial Computers/etc, it is only a matter of time before technology becomes capable of magic.</p><p>As such, Magic Quidditch is inevitable. It is bound to happen and has the potential to be the first mixed electronicotraditional sport.</p><p>All the technology that you need to build it already exists, it&#8217;s mostly a matter of sticking all legos in the right order. Once you have it, all that is left is gather all the public into a stadium, stick a Spatial Computer in front of their eyes and let them enjoy the show.</p><p>That computer is not yet available in the quantity/price that would befit such an event but you can be sure that by the time you are done building your project this situation will have become absolutely acceptable.</p><p>And for as much this Reality is Mixed, so are my feelings about the upcoming era. We are about to go through the most incredible experiences that Humankind ever created &#8212; only bound by our own imagination. Yet few of it will be physical. What will this new reality cost to our civilization?</p>]]></content:encoded></item><item><title><![CDATA[Confront your greatest fear and parse a string with a Regular Expression]]></title><description><![CDATA[In this blog we usually talk about tech management but let's have a refreshing tutorial on a less advanced topic!]]></description><link>https://www.baby-cto.com/p/confront-your-greatest-fear-and-parse</link><guid isPermaLink="false">https://www.baby-cto.com/p/confront-your-greatest-fear-and-parse</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Mon, 01 Apr 2024 19:04:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/76d938da-e203-43d6-b7a4-02b4938b9964_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Regular expressions are a scary thing and can take quite a while to be digested &#8212; even for mid-level developers. Many useful tools such as <a href="https://regex101.com/">regex101</a> that will decode the syntax for you or <a href="https://www.debuggex.com/">debuggex</a> which will let you visualize the expression as finite state machine.</p><p>But nothing like putting your hands in the dirt to understand how something really works! Something that eluded me for years is how you could parse a string &#8212; and in particular if there is an escaped quote in it?</p><p>Let&#8217;s start with the beginning. We want to match a basic string. Regular expressions are expressed in JS.</p><pre><code># To match
"hello"

# Regxp
/".*"/</code></pre><p>The structure is simple: first a quote, then any character any number of time, then another quote. But in real life you&#8217;re probably working on a parser. For example:</p><pre><code>&lt;something foo="bar" bar="foo" /&gt;</code></pre><p>In this case the regular expression is going to get greedy and return <code>"bar" bar="foo"</code>, which is not what we want.</p><p>The first trick is probably to tell the regular expression not to be greedy by using the <code>?</code> symbol.</p><pre><code># To match
&lt;something foo=<strong>"bar"</strong> bar=<strong>"foo"</strong> /&gt;

# Regular expression
/".*<strong>?</strong>"/</code></pre><p>That&#8217;s fine but now if like in most cases you want to allow your users to have quotes in the string by escaping them, you&#8217;ll be out of luck. This for example will not work:</p><pre><code>const name = "Dwayne \"The Rock\" Johnson";
// Will match: "Dwayne \" and " Johnson"</code></pre><p>This part got me perplexed for the longest time. There are different ways to solve it, my personal favorite is to consider what we want to allow within our string. Namely:</p><ul><li><p>Any character that isn&#8217;t an end quote is fine: <code>[^"]</code> in regex language (<code>^</code> is for <em>not</em>)</p></li><li><p>Any escape sequence &#8212; aka something that starts with a backslash: <code>\\.</code> in regex</p></li></ul><p>Since we don&#8217;t want the first match to eat up the second match (afterall a &#8220;backslash&#8221; is &#8220;not a quote&#8221;), we&#8217;ll make sure to put them in the right order so that the matching can happen easily.</p><pre><code># To match
const name = <strong>"Dwayne \"The Rock\" Johnson"</strong>;

# Regular Expression
/"(<strong>\\.</strong>|<strong>[^"]</strong>)*"/</code></pre><p>And that&#8217;s it! You are now matching an escaped string. Not that scary anymore?</p><p>Let&#8217;s study the second method, that I&#8217;ve found <a href="https://github.com/lark-parser/lark/blob/d676df9b888ead42daffd31c035d95241bff0920/lark/grammars/common.lark#L23">inside of Lark</a> (amazing package by the way). It&#8217;s both simpler and more confusing and does not work with older JavaScript engines, but let&#8217;s go into it.</p><p>Essentially, if you say that &#8220;escaped quotes must not terminate the string&#8221; then it means that &#8220;the last quote of the string can&#8217;t be escaped&#8221;. That&#8217;s something we can easily check with a negative assertion:</p><pre><code># To match
const name = <strong>"Dwayne \"The Rock\" Johnson"</strong>;

# Regular Expression
/".*?<strong>(?&lt;!\\)</strong>"/</code></pre><p>The novelty here is that instead of just having a non-greedy match-all ( <code>.*?</code> ), we&#8217;re adding at the end an assertion <code>(?&lt;!\\)</code> to check that there is no backslash before the end. This has however a drawback, it&#8217;s that you can&#8217;t escape a backslash right before the end of the string, because then the last quote would be preceded by a backslash (still with me?). In short, this doesn&#8217;t work:</p><pre><code>const effect = "Domino \\";</code></pre><p>But fortunately, we can allow to terminate the string with quoted backslashes!</p><pre><code># To match
const effect = <strong>"Domino \\"</strong>;

# Regular Expression
".*?(?&lt;!\\)<strong>(\\\\)*?</strong>"</code></pre><p>And here we are! Matching strings another way.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/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.baby-cto.com/subscribe?"><span>Subscribe now</span></a></p><p>Let&#8217;s hope that this problem-oriented walkthrough helped you understand relatively advanced thought patterns in regular expression. Often you&#8217;ll walk on problems that can seem intractable without the proper knowledge but which can easily be unlocked if you master regular expressions &#8212; or better even: parsers! But that&#8217;s for another article.</p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[From Chaos to Clarity: Streamlining End-to-End Testing with Django and SvelteKit]]></title><description><![CDATA[Learn the secrets to boosting your web development process with Django and SvelteKit. Our article reveals how to seamlessly blend these powerful frameworks for unmatched speed and reliability.]]></description><link>https://www.baby-cto.com/p/from-chaos-to-clarity-streamlining</link><guid isPermaLink="false">https://www.baby-cto.com/p/from-chaos-to-clarity-streamlining</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sun, 10 Mar 2024 08:00:44 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f06f52f0-4532-4a49-a284-684e77625374_1792x1024.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For reasons listed in my <a href="https://model-w.readthedocs.io/en/latest/architecture.html#back-end-django">Model W Architecture</a> document, my framework of choice for the backend is Django (tldr; the ORM) and until another better option emerges in the world of JavaScript this is not going to change. On the other hand, my experience has shown that if you do a professional website you will eventually outgrow the <a href="https://htmx.org/">htmx</a> and other lightweight frameworks, making it a necessity to systematically turn towards meta-frameworks such as <a href="https://kit.svelte.dev/">SvelteKit</a>, Nuxt, Nuxt.js or Astro &#8212; to quote the most famous.</p><p>This is what we&#8217;re systematically doing at <a href="https://with-madrid.com/">WITH</a> and the combination works well. But you absolutely must figure ways to align all this properly &#8212; and there are no official ways to do this.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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>Today we&#8217;re going to explore one specific friction point: end-to-end testing.</p><h2>Why to test?</h2><p>Some will tell you that you need to cover 100% of your code base with unit <em>and</em> e2e tests while others will say &#8220;testing is doubting&#8221;. So while we&#8217;re not here for a theoretical lesson on the benefits of tests, we are goingt to focus on <em>why</em> we would want to have those, which in turns allows us to decide what we want to test.</p><h3>The speed factor</h3><p>First, nobody gets the code right the first time. Personally with my 20 years of coding I think that <em>once</em> I managed to land about 1000 lines of code that worked on the first time, while being extremely focused on what I was doing. The typical development cycle looks more like: write a bunch of lines, see where it breaks, repeat until it works.</p><p>As a developer, you will learn to code faster and with less mistakes over time but there is nothing you can do about it <em>right now</em>. Just code more and it will sink in. This leaves you with the second part of the process: how fast can you see where it breaks?</p><p>Obviously the answer to that question is largely dependent on what you are currently testing. If you&#8217;re talking about CSS, then a second screen with the page you&#8217;re currently integrating along with a good meta-framework that implements <a href="https://webpack.js.org/concepts/hot-module-replacement/">HMR</a> properly should be the easiest way to go.</p><p>On the other hand if you&#8217;re creating Django models and/or APIs using <a href="https://www.django-rest-framework.org/">DRF</a>, a lot of the code that you are going to write is going to be declarative &#8212; only to be later picked up by the meta functions of Django and turned into a usable project. Which means that there is literally no code for you to test, it&#8217;s mostly configuration<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><p>But if you are working on the typical front/back architecture that we&#8217;ve discussed earlier, most of the things that you&#8217;re ever going to want to test in an automated way are the end-to-end user stories.</p><p>If you test those manually, you will be clicking on many buttons and filling up many forms. On and on again. For test cycles of 30 seconds to 5 minutes usually.</p><p>On the other hand if you automate those tests you can probably drop the testing time to a couple of seconds. We can estimate that on average it&#8217;s going to be about 10 times faster than manual testing.</p><p>Now let&#8217;s consider the following simple equation:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;T = \\sum_{n=1}^{R} (T_c + T_t) = R \\cdot (T_c + T_t) \\quad \\text{where} \\quad \n\\begin{cases}\nT_c = \\text{Time spent coding} \\\\\nT_t = \\text{Time spent testing} \\\\\nR = \\text{Number of repetitions} \\\\\nT = \\text{Total time to develop a feature}\n\\end{cases}\n&quot;,&quot;id&quot;:&quot;OXPHUBHXCF&quot;}" data-component-name="LatexBlockToDOM"></div><p>Let&#8217;s consider that:</p><ul><li><p>The time spent testing manually is equal to the time spent coding</p></li><li><p>The automated test is 10 times faster than the manual test</p></li></ul><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{align*}\nT &amp;= R \\cdot (T_c + T_t) = R \\cdot (2T_t) \\quad &amp;\\text{since $T_c = T_t$} \\\\\nT' &amp;= R \\cdot (T_c + T_t') = R \\cdot \\left(T_t + \\frac{T_t}{10}\\right) = R \\cdot \\frac{11T_t}{10} \\quad &amp;\\text{since $T_t' = \\frac{T_t}{10}$} \\\\\n   &amp;= R \\cdot \\frac{11}{10} \\cdot T_t = \\frac{11}{20} \\cdot R \\cdot (2T_t) \\\\\n   &amp;= \\frac{11}{20} \\cdot T \\quad &amp;\\text{rearranging terms} \\\\\n\\therefore T' &amp;= \\frac{11}{20} \\cdot T\n\\end{align*}\n&quot;,&quot;id&quot;:&quot;EDGOETYQPJ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Even if you don&#8217;t understand the math formalism, you understand that in the end testing your code automatically while you develop is <strong>almost twice faster</strong>. The bias here of course is that you still need to write this test. That&#8217;s why we&#8217;ll explore tools that make this as easy as possible, so that the benefits are not swallowed by the plumbing.</p><p>Overall it&#8217;s hard to quantify exactly <em>how much</em> productivity gain<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> we&#8217;re talking but it should help you go about two times faster &#8212; and in the worst case scenario it seems unlikely that it will be slower than testing manually. More importantly we&#8217;re just talking about the <em>immediate</em> benefits of testing.</p><h3>Ease of mind when changing things</h3><p>Any application that lives long enough will reach the point where no single human brain can comprehend the entirety of its features at the same time. There are just too many moving parts. And this point arrives much sooner than you think, especially in environments like mine where people move from project to projet all the time.</p><p>Essentially: how do you know if something that you change will break anything in the project without testing everything? Leading to the subsequent question: how do you even know what to test?</p><p>The answer is that you cannot know what broke if you don&#8217;t test it, so indeed you <em>have to</em> test everything. Which can be done with for example a large testing booklet written and maintained manually &#8212; aka not &#8212; or also with automated tests that run every time you push  your code into the repo (and on your machine while you dev).</p><p>The second option is absolutely better in the sense that:</p><ul><li><p>If all the tests are written, it will be exhaustive</p></li><li><p>And since it&#8217;s all automated, each test should be extremely fast</p></li></ul><p>This way you reduce a QA process to a few seconds of test instead of potentially hours of man time spent. With the guarantee that everything is executed in stable conditions and in a repeatable way.</p><h3>Onboarding of newcomers</h3><p>Overall tests will show you how to use the app and how to use the code. All a newcomer has to do to understand everything that you can do with the application is to watch the tests unfold.</p><p>Let&#8217;s note that this is partly true because tests will often be cryptic and hard to document. A better way to approach this topic is with <a href="https://en.wikipedia.org/wiki/Behavior-driven_development">BDD</a> and &#8212; spoiler alert &#8212; <a href="https://pytest-bdd.readthedocs.io/en/stable/">pytest-bdd</a>. But that&#8217;s for another article, we are focused here on the Django/Svelte integration.</p><h2>Picking the right tools</h2><p>While I am not going to list every single test runner and framework out there &#8212; that would be an entirely different article &#8212; here are the constraints I&#8217;m settings for myself in this quest for automated tests.</p><p>The first aspect is that Django-based tests have the ability to write directly into the database, which is in turn cleaned up after each test. When your application is essentially just transforming a DB schema into an API, that&#8217;s really something you want to be able to do. Without that you&#8217;re in for some very awkward mocking. The core idea is thus to run tests from Django &#8212; I even considered wrapping Django&#8217;s tests from JS but in the end that was not necessary.</p><p>The default test framework in Django is the standard <a href="https://docs.python.org/3/library/unittest.html">unittest</a>, and while honorable there are more friendly and powerful options out there. Namely <a href="https://docs.pytest.org/en/8.0.x/">pytest</a>, which as you will see right below will be the backbone of our strategy. The first thing is to integrate it with Django&#8217;s tests and this happens with <a href="https://pytest-django.readthedocs.io/en/latest/">pytest-django</a>.</p><p>The main issue however that I have with testing in Django is that, while it has a <a href="https://docs.djangoproject.com/en/5.0/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a> (and the <a href="https://pytest-django.readthedocs.io/en/latest/helpers.html#live-server">pytest equivalent</a>), it kinds of wants you to use <a href="https://selenium-python.readthedocs.io/">Selenium</a> and no offense for that precursor tool but oh boy is it unusable. Last time I wrote e2e tests with Django and Selenium I ended up writing more utils than tests.</p><p>Thankfully things have changed and we are now able to use <a href="https://playwright.dev/python/docs/intro">Playwright</a> through the <a href="https://pypi.org/project/pytest-playwright/">pytest-playwright</a> plugin. While I don&#8217;t particularly like Microsoft I must admit that it has two very interesting characteristics.</p><p>Firstly it has very semantic selectors which will use accessibility attributes in order to find elements on the page. This is great because while you test your features you know that if you don&#8217;t have to resort to crude CSS selectors it means that at least what you test looks more or less decent in terms of accessibility.</p><p>And secondly it has an auto-wait feature on all the selectors, which is by far the most annoying thing that you end up doing all the time with Selenium.</p><p>To summarize, we&#8217;re going to go with:</p><ul><li><p><code>Django</code> itself and its testing facilities</p></li><li><p><code>pytest</code> as test runner</p></li><li><p><code>pytest-django</code> for the Django integration</p></li><li><p><code>pytest-playwright</code> for the browser testing</p></li></ul><h2>Implementation time!</h2><p>In order to proceed to demonstrate how all those tools work together, created a <a href="https://github.com/Xowap/e2e-django-svelte">sample project</a> on GitHub which contains mostly the boilerplate that you will need along with an example of how to use everything together.</p><p>The project is extremely simple in itself: there is one model that is exposed through an API with one page that displays all the instances returned by the API. Really just the bare minimum to write a test that shows all we discussed above.</p><p>Lots of small details are going to be left out from this explanation that focuses on the big picture. The source code being entirely available, any shadow can be lifted by inspecting it. If you intend to run the project yourself, have a read at the <a href="https://github.com/Xowap/e2e-django-svelte/tree/c1b5298acce4f236d2a4fa372fc85e18f8c2577e">README</a>.</p><h3>Boilerplate</h3><p>We&#8217;ve got two projects which are fairly close to default Django and SvelteKit projects located in the <a href="https://github.com/Xowap/e2e-django-svelte/tree/c1b5298acce4f236d2a4fa372fc85e18f8c2577e/api">api</a> and <a href="https://github.com/Xowap/e2e-django-svelte/tree/c1b5298acce4f236d2a4fa372fc85e18f8c2577e/front">front</a> folders.</p><h4>API</h4><p>Let&#8217;s first have a look at <a href="https://github.com/Xowap/e2e-django-svelte/blob/c1b5298acce4f236d2a4fa372fc85e18f8c2577e/api/requirements.in">our dependencies</a>. Quite obviously we&#8217;ll see there Django alongside its best friend <a href="https://www.django-rest-framework.org/">DRF</a> for the API management part.</p><p>On the testing side we have 3 plugins on top of pytest:</p><ul><li><p><code>pytest-django</code> &#8212; Takes care of the Pytest/Django integration, and specifically takes care of managing the database and live server</p></li><li><p><code>pytest-playwright</code> &#8212; Integration of Pytest and Playwright in order to be able to test things within a browser</p></li><li><p><code>pytest-env</code> &#8212; Small utility that allows to define environment variables when Pytest runs, which is super useful if like me you follow the <a href="https://12factor.net/">12 factors philosophy</a>: it allows to have a static configuration for running tests.</p></li></ul><p>Since we&#8217;re talking about end-to-end tests, I figured that it would not necessarily make sense to pin them to a specific Django app and rather I&#8217;ve created a dedicated <a href="https://github.com/Xowap/e2e-django-svelte/tree/c1b5298acce4f236d2a4fa372fc85e18f8c2577e/api/tests">test folder</a> for it.</p><p>In order to be able to run the tests, you need to make sure to configure the settings modules and the environment in the <code>pyproject.toml</code> file:</p><pre><code>[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "e2e_django.settings"
env = [
    "DJANGO_ALLOW_ASYNC_UNSAFE=true",
]</code></pre><h4>Front</h4><p>Honestly I&#8217;ve changed nothing to the front-end except create the page that displays the thing we want to test.</p><h3>Front/API sync</h3><p>The part that was elusive to me for the longest time was: how can I synchronize the front-end and the back-end &#8212; especially in regards to the database management that I&#8217;m mentioning earlier.</p><p>Turns out, with a little bit of eblow grease and pytest magic it&#8217;s fairly easy.</p><p>First we need to talk about pytest&#8217;s <a href="https://docs.pytest.org/en/6.2.x/fixture.html">fixtures</a>. If you&#8217;re a Django developer you probably hear &#8220;fixture&#8221; and think &#8220;right to load data into the database&#8221;. But it&#8217;s not that at all. They are a mechanism of dependency injection specialized for tests.</p><p>For example you could say: I have a &#8220;user&#8221; fixture that is a user from the database and that is scoped to each individual test. If a test requires the &#8220;user&#8221; fixture then the user will be created into the database and will be cleaned after each test.</p><p>Both the Playwright and the Django plugin use them heavily for giving you access to their various features. Typicall if you ask the <code>page</code> fixture for your test then Playwright will be started but ohterwise it will not.</p><p>The same applies for the <code>live_server</code> from Django and in our case we&#8217;ll be able to leverage this in order to start and stop the front-end while testing.</p><p>This can be done relatively easily if you exploit the fact that both the front and the API are in the same repository. You can compute accurately the absolute path of the front-end and start scripting there.</p><p>Which is exactly what the <a href="https://github.com/Xowap/e2e-django-svelte/blob/c1b5298acce4f236d2a4fa372fc85e18f8c2577e/api/tests/conftest.py#L64">front_server()</a> and its friends are doing in the conftest.py file &#8212; a file that can inject global fixtures into different tests under the same module. While you can read the source code directly, let&#8217;s review the key points:</p><ul><li><p>We use Popen to start the Vite server in preview mode, which is close enough to production for our needs. A fixture can just yield an object, and the function will suspend until all tests that need it are done. This is what we do, and after the yield finishes we just shut down the process.</p></li><li><p>The process is bound to port 0. This is a special way to tell the system &#8220;just pick any available port&#8221;. Which allows to not have to decide for a static port number thus limiting the risks of failure. The Vite server will print the chosen port when starting, so we just parse stdout to get it.</p></li><li><p>In the end we simply yield the base URL of this front-end server and then our tests will be able to connect to it in any way they want.</p></li></ul><p>This example is done with Vite because that is what powers SvelteKit, but while the detail of the commands you would have to run would be different there are equivalents of this in every single front-end framework so you&#8217;ll just need to adapt it accordingly.</p><h3>Writing the test</h3><p>Now that we&#8217;re able to summon the front-end (through the code above) and the browser (through Playwright) it&#8217;s time for us to write a test!</p><p>Be careful, this is actually very disappointing because it&#8217;s way too simple. First we create the items that we want to see through a fixture:</p><pre><code>@pytest.fixture
def some_items(transactional_db):
    return [
        Item.objects.create(name="Foo"),
        Item.objects.create(name="Bar"),
    ]</code></pre><p>Now we create a test that requires 3 fixtures:</p><ul><li><p><code>front_server</code> &#8212; The server we&#8217;ve created above</p></li><li><p><code>some_items</code> &#8212; The items defined here</p></li><li><p><code>page</code> &#8212; The Playwright control object</p></li></ul><pre><code>@pytest.mark.django_db(transaction=True)
def test_content(front_server, some_items, page: Page):
    page.goto(str(httpx.URL(front_server).join("/")))

    for item in some_items:
        item_name_escaped = repr(item.name)[1:-1]
        assert (
            page.locator(f"li:has-text('{item.id}: {item_name_escaped}')").count() == 1
        )</code></pre><p>This way we&#8217;re able to send the browser to the front-end and check the content of the page based on the expected items we&#8217;re looking for. That&#8217;s it!</p><h3>Running the GitHub Action</h3><p>If you&#8217;re making automated tests, it&#8217;s usually a good idea to run them automatically. Fortunately it&#8217;s really easy to do with GitHub Actions. We&#8217;ll define <a href="https://github.com/Xowap/e2e-django-svelte/blob/c1b5298acce4f236d2a4fa372fc85e18f8c2577e/.github/workflows/test-api.yml">a workflow</a> that triggers on push.</p><p>Beyond the installation of dependencies, let&#8217;s check some interesting steps of that workflow:</p><pre><code>- name: Run tests
    run:
        .venv/bin/python -m pytest --junitxml=/tmp/test-results.xml
        --tracing=on --video=on --screenshot=on
    working-directory: ./api</code></pre><p>When running the tests, we keep the results in JUnit format and ask Playwright to record pictures and videos of all tests. Let&#8217;s note that if your project scales up you probably just want to record failing tests and not all tests, otherwise you&#8217;ll eat up artifact storage pretty quick.</p><pre><code>- name: Publish test report
    uses: mikepenz/action-junit-report@v4
    if: always()
    with:
        report_paths: "/tmp/test-results.xml"
        check_name: "API Pytest Report"</code></pre><p>Since we&#8217;re able to export the outcome as a a JUnit file, we use an action that transforms it into a nice recap for the action.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ld3F!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ld3F!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 424w, https://substackcdn.com/image/fetch/$s_!ld3F!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 848w, https://substackcdn.com/image/fetch/$s_!ld3F!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 1272w, https://substackcdn.com/image/fetch/$s_!ld3F!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ld3F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png" width="550" height="173.92300641613198" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:345,&quot;width&quot;:1091,&quot;resizeWidth&quot;:550,&quot;bytes&quot;:34732,&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_!ld3F!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 424w, https://substackcdn.com/image/fetch/$s_!ld3F!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 848w, https://substackcdn.com/image/fetch/$s_!ld3F!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 1272w, https://substackcdn.com/image/fetch/$s_!ld3F!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfc80dc0-f86f-4dcb-960b-e1f2317cc8e1_1091x345.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Test summary from the GitHub Action (only visible if you&#8217;re connected)</figcaption></figure></div><pre><code>- name: Keep Playwright artifacts
    uses: actions/upload-artifact@v4
    if: always()
    with:
        name: playwright-traces
        path: api/test-results/</code></pre><p>Finally, we&#8217;ll save temporarily the Playwright videos and screenshots into a GitHub Action artifact, which allows to analyze in-depth failed tests (for example using the online <a href="https://trace.playwright.dev/">Trace Viewer</a>).</p><h2>Conclusion</h2><p>After establishing that automated testing is well-worth going through the trouble of establishing a well-oiled testing infrastructure, we set to explore how this can be accomplished with Django and a Javascript meta-framework such as SvelteKit.</p><p>While this requires a little bit of boilerplate and adaptation &#8212; after all, those two worlds are not exactly thought to work togeter &#8212; we can see that we can obtain both the convenience of Django&#8217;s tests with their database management and the power of modern front-end test frameworks such as Playwright.</p><p>In the end the tests run completely autonomously on GitHub Actions and produce both nice reports and in-depth traces that allow analysis in case of failure.</p><p>This whole structure is easy to use on a daily basis and can boost your coding speed up to two times!</p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>For a broad meaning of configuration. And of course you can write specific functions and algorithms in the backend, for which the use of unit tests is perfect. But the vast majority of the code you&#8217;re writing in a Django project is actually written by Django. Which is why I like Django.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>If anyone has heard of a valid experiment on the topic, I&#8217;ll take. What I&#8217;ve found is mostly studies on 12 subjects so I&#8217;m not going to take that as too solid.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Entrepreneur 101: increase your brain power]]></title><description><![CDATA[Explore strategies to manage ADHD and decision fatigue for entrepreneurs. Learn time management, meal prep, and automation tips to boost productivity and mental clarity.]]></description><link>https://www.baby-cto.com/p/entrepreneur-101-increase-your-brain</link><guid isPermaLink="false">https://www.baby-cto.com/p/entrepreneur-101-increase-your-brain</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sun, 03 Mar 2024 08:00:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/2962677d-45e1-42ed-9c4e-8f30e9c02b52_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The drama of our brain &#8212; and especially with ADHD brains &#8212; is that taking any single decision will eat up some mental energy that you will only recover when getting proper rest. And this whether you are taking a critical life-or-death decision or decide which item to get from McDonald&#8217;s. On the other hand, being an entrepreneur requires so much decision-making that it would give ADHD<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> to neurotypicals.</p><p>So how do you increase the amount of decisions you can take? In a way you can&#8217;t, because of what I said. But on the other hand, you can by focusing yourself on the decisions that matter.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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>The question now becomes: how do you automate the decisions that do not matter? Some call me psycho, but here are the strategies that I&#8217;ve applied throughout my life to avoid useless choices.</p><h2>Time management</h2><p>Managing your time and priorities is a daunting task. A million things more urgent one than the other try to grab your attention. And if you&#8217;re like me, most likely you will just hyperfocus on the fun thing of the moment and forget completely about the rest. Which for the longest time has been my time management technique: just focus on one thing at a time, for one month or more straight.</p><p>And if you are bootstrapping it&#8217;s probably fine even though it can hurt you in the sense that you get completely blindsided by what you are doing and never take the time to do basic things such as checking for competitors, exploring advices that you&#8217;ve received or even simply looking for solutions that are not 100% in-house development.</p><p>Instead, you need to get a scheduler such as <a href="https://reclaim.ai/">Reclaim</a>, which is now my god and master, commanding my actions through my agenda.</p><p>The first thing it does is take a todo list and schedule it. If I&#8217;m able to break down the things I have to do into small, actionable tasks (that can later be extended or shortened) then it will automatically schedule all of them around my meetings and other obligations, while also making sure that everything moves in parallel and in accordance with their respective priorities and deadlines.</p><p>The other thing is that it allows to plan 1:1 meetings with your team. As you become a manager it&#8217;s essential to talk to your developers regularly and if you&#8217;re like me with no notion of time then 6 months can happen without realizing you didn&#8217;t follow up on anyone from your team. It will find the time for this in your agenda and make it happen.</p><p>Lastly it will allow you to have various rituals like checking your mails or monitoring tools. Super useful to keep an eye on things regularly while also working like crazy on other stuff.</p><p>Overall, Reclaim has massively decreased the amount of decisions that I need to take on a weekly basis, allowed me to multitask while it was previously impossible for me and also allows me to have an idea of when I&#8217;m going to be able to deliver a specific task.</p><h2>Food</h2><p>Don&#8217;t get me wrong I am a huge foodie and in fact spend most of my holidays hunting down restaurants and bars to discover local tastes. But let&#8217;s not get confused: there is eating as a hobby and there is eating because otherwise you&#8217;ll faint on your keyboard. I&#8217;m talking about the second one here.</p><p>Depending on your personal preferences, revenue levels and overall situation, different tactics can apply. For myself I&#8217;ve had the following ones:</p><p><strong>Frozen dishes</strong>. The basic version is to  go to your local frozen foods supermarket (<a href="https://www.picard.fr/">Picard</a> in France), stack up a month&#8217;s worth of food in your cart and store this in your freezer. While highly criticized by friends and roomates for this practices, I believe that it is a relatively balanced and extremely efficient way of managing your meals. Not to mention cheap, since I&#8217;ve basically been going through my student years and early entrepreneur stages with this technique.</p><p><strong>Food subscriptions</strong>. In the same vein but definitely tastier and healthier you will see subscription services like <a href="https://wetaca.com/">Wetaca</a> in Spain. Did not always exist, not sure how easy is it to find over the globe, but overall a cheap and efficient way to get relatively balanced meals. It&#8217;s what I&#8217;m currently doing most of the time and it&#8217;s great, they even change the menu for me and I don&#8217;t need to decide anything.</p><p><strong>Recipe round-robin</strong>. Entrepreneur life has highs and lows and there was a short period during which I had to dip below the poverty line. Not a great time but probably the healthiest eating habits I&#8217;ve ever had. What I did was create about 5 to 10 recipes that took 5 minutes to cook then go to the market every week-end to buy the products directly from the producer and then cook just those recipes on repeat.</p><p><strong>Fast-food obsession</strong>. My theory about fast food is that it&#8217;s only good if you can eat it every day of the week at every meal. When I lived in India I used to work in an IT building where all there restaurants were of a mediocre quality and it was becoming quite hard to alternate between the same dishes all the time. Eventually I ended up eating McDonald&#8217;s for every literal meal from breakfast to dinner. Never lost so much weight so fast for some reason. Anyways, it&#8217;s not a healthy option but if you don&#8217;t abuse you can get through a hard year or two without issue using this strategy.</p><p>Overall, it&#8217;s important to place your bets in accordance to what works for you.</p><h2>Transport</h2><p>So surely you&#8217;ll want to move around. For example to go to work, to meet clients, etc. Let&#8217;s see how you can avoid useless pain in the process.</p><p>The first strategy to optimize transport is to not need transport. Start your company from your home, work remotely and save up on an office, etc. Can be daunting for the mental health, but for a time it is a good fix.</p><p>Another important point &#8212; except if you&#8217;re american I guess? &#8212; is to live in a densely populated area. By having all necessities close-by you avoid yourself complicated trips and can instead walk there most of the time. Which is especially important for the next point as well&#8230;</p><p>Don&#8217;t have a car. Cars are commonly known as money hogs because of the price you need to pay and on top of all the mechanical issues you&#8217;re going to get with it. People reading this claim that this statement is due to the fact I don&#8217;t have a driver&#8217;s license &#8212; and it is linked &#8212; but it&#8217;s also that up until recently I could not afford one in terms of costs and in terms of mental load. Instead, public transportation, taxis or car rental can often be a more economic option and a much lower mental load. Of course, YMMV.</p><h2>Shopping</h2><p>During my early years as an entrepreneur, the Christmas period was quite a stressful one. On top of being generally a very dense period in terms of work &#8212; client&#8217;s budgets need to be spent before the end of the year &#8212; you also need to think which gifts you&#8217;re going to get for your family. And when you pay yourself with one peanut on a half, the issue becomes quite the balancing act.</p><p>You basically end up going around all the shops of the city  center fishing for ideas and taking notes of what could potentially be the best combination of things you could generate.</p><p>This was an issue until I realized that all I had to do &#8212; and sorry if it sounds obvious to everyone now &#8212; was to shop online. Instead of physically spending your energy walking a hundred thousand steps over your Saturday afternoon, you can simply switch from tab to tab, order and wait for things to arrive home.</p><p>These days I&#8217;m almost never buying anything in physical stores. Which can be pushed even further with delivery apps. Since they allow you to search items by name it gives you an index of all the objects and brands you can find in various stores. Want to drink your favorite kind of beer within the next 30 minutes and you don&#8217;t know where to find it? Type the name in Glovo and you&#8217;ll get a completely random kebab shop open at 2am which can ship it to you.</p><h2>Administrative emails</h2><p>If you&#8217;re like me you probably hate replying to emails, especially those that have few connection to your actual business. Administrative stuff, tax declarations, getting refunds from an e-commerce, etc. But I&#8217;ve managed to lower the cost of doing so substencially by using ChatGPT in a strategic way.</p><p>First I&#8217;ll take the email/message and ask ChatGPT to summarize what it says, figure what they want from me and give me options of what actions I could take.</p><p>Then I&#8217;ll pick an option and ask ChatGPT to reply accordingly. I&#8217;ll say it in my words, not constructed, not polite. And then it will write an nice long polite answer that says exactly what I need. Copy/pasta, send and done. Such a relief to proceed this way!</p><h2>Entertainment</h2><p>It&#8217;s important as a founder to change your mind from work regularly, otherwise you&#8217;d just become completely crazy. In terms of entertainment however, everyone got their jam so I&#8217;m not going to get super exhaustive, but let&#8217;s throw a few ideas.</p><p>Obviously everyone is going to have some kind of VOD subscription, but I also like to structure my entertainment around no-decision options.</p><p>It&#8217;s going to sound dumb, but TV is a good option. Especially paid cinema channels. Turn on your TV in the evening on a channel that you know you enjoy and you&#8217;ll for sure see something fresh wihtout spending any neuron on chosing it. On top if that it can rythm your day if you work from home and give you a motivation to stop working.</p><p>Another thing I like to do is to show up in big <a href="https://en.wikipedia.org/wiki/Bobo_(socio-economic_group)">bobo</a> cinema in the heart of Paris and picking a movie randomly on a combination of what is showing in the next hour and what posters are catching my eye. No reading synopsis, nor thinking what the movie is going to be about&#8230; I&#8217;ve seen amazing movies like that, totally recommend.</p><h2>Conclusion</h2><p>You could read this article thinking: why is idiot flaunting his lazyness over the Internet, but that would be missing the point. Throughout my life I&#8217;ve had to deal with a termendous workload and fairly low executive planning skills. You cannot do it all. And yes a lot of the techniques mentioned here are individually obvious if you start considering the issue but what matters most is to create for yourself a consistent way of life with the right combination of everything that makes your life as unloaded as possible, leaving your brain free to think what will make a difference in your business.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>ADHD is defined by the symptoms and not the root cause. So if your life gets overloading, you can develop ADHD just because you have too many things going on.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Hands on! Parse your emails with Google's Gemma]]></title><description><![CDATA[Brave the impossible and use only your CPU to transform your emails into machine-readable semantic JSON files which can then be interpreted by personal assistants, finance tools, etc.]]></description><link>https://www.baby-cto.com/p/hands-on-parse-your-emails-with-googles</link><guid isPermaLink="false">https://www.baby-cto.com/p/hands-on-parse-your-emails-with-googles</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sun, 25 Feb 2024 08:00:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/990b4c02-36f5-4322-8f4a-41ce4f0d789e_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As I explained in my <a href="https://babycto.substack.com/p/jobs-for-llms-and-how-to-survive">previous post</a>, LLMs are not good at everything but they&#8217;re particularly good at parsing information and transforming it into another format. It&#8217;s a technique that we use everywhere <a href="https://www.chatfaq.io/blog/ai-snack-guided-llm-generation-shaping-language-models-to-meet-your-needs">in ChatFAQ</a> for example.</p><p>Today we&#8217;re going to dive into the code that lets us do this. The goal is simple:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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><ol><li><p>First we&#8217;ll classify the email to know what kind of email it is. Yeah I said that it&#8217;s not a great idea because LLMs are not super performant for that. I&#8217;ve tried my best, it seems to work well with GPT-4 and more or less decently with Gemma.</p></li><li><p>And then for each type of email we&#8217;re going to extract a JSON which tells us in a machine-readable format the content of that email.</p></li></ol><p>I&#8217;ll walk through the main elements of the code, if you want to follow up with the completed project it&#8217;s <a href="https://github.com/Xowap/semmail">all on GitHub</a>.</p><p>Also, of course there are many libraries and frameworks and whatnots to help you do this in different ways, but we&#8217;re here to learn so we do all by hand today.</p><p>Buckle up and let&#8217;s go!</p><h2>The flask app</h2><p>In order to do this, we&#8217;re going to make a Flask app which exposes:</p><ul><li><p>A basic page that allows to upload an email in the .eml format (what you get when you &#8220;Download this email&#8221; from Gmail for example).</p></li><li><p>An API which for a given email gives you the semantics of it.</p></li></ul><p>We&#8217;ll do that in a very small <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/app.py">src/semmail/app.py</a> file.</p><p>First, a super basic view which is just a form that will call the API when submitted.</p><pre><code>@app.route("/")
def home():
    """Just a dumb form where you can upload a file to the API"""

    return render_template_string(
        """
        &lt;!DOCTYPE html&gt;
        &lt;html&gt;
        &lt;head&gt;
            &lt;title&gt;Upload File&lt;/title&gt;
        &lt;/head&gt;
        &lt;body&gt;
        &lt;h2&gt;Upload File&lt;/h2&gt;
        &lt;form action="/upload" method="post" enctype="multipart/form-data"&gt;
            &lt;input type="file" name="email_file"&gt;
            &lt;input type="submit" value="Upload"&gt;
        &lt;/form&gt;
        &lt;/body&gt;
        &lt;/html&gt;
    """
    )</code></pre><p>Then the API itself. We&#8217;re going to expect that there is a function that takes an email as input and returns the parsed output.</p><pre><code>@app.route("/upload", methods=["POST"])
def upload_file():
    """After a very basic validation of the file, we put it through the LLM
    so that we can know what it's about."""

    if "email_file" not in request.files:
        return jsonify({"error": "No file part"}), 400

    file = request.files["email_file"]

    if file.filename == "":
        return jsonify({"error": "No selected file"}), 400
    try:
        file_content = file.read()
        result = interpret_email(file_content)
        return jsonify(result), 200
    except ValueError as e:
        return jsonify({"error": str(e)}), 400</code></pre><p>In the middle of the boilerplate, you&#8217;ll figure the <code>interpret_email()</code> function. For now it can just return a static structure, we&#8217;re going to implement it in a moment.</p><h2>Calling the AI</h2><p>Because in the project I want to have an OpenAI and a Gemma implementation I&#8217;ll have <a href="https://github.com/Xowap/semmail/tree/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/ai">two modules</a> in the GitHub but I&#8217;ll only cover Gemma because it&#8217;s the hot new kid that everyone wants to play with.</p><h3>Make the instance</h3><p>The first thing you need to do is to go to the model&#8217;s <a href="https://huggingface.co/google/gemma-2b-it">HuggingFace page</a> and use your account to accept the license. Then go to your settings and fetch an API key that you&#8217;ll need to put in the project&#8217;s <code>.env</code>.</p><pre><code>HUGGINGFACE_TOKEN=xxx</code></pre><p>This will allow us to create the instance of the tokenizer and the model in our <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/ai/gemma.py">src/semmail/ai/gemma.py</a> file. Put at the root of the module:</p><pre><code>model_id = "google/gemma-2b-it"

if torch.cuda.is_available():
    device = "cuda"
else:
    device = "cpu"


tokenizer = lazy_object_proxy.Proxy(lambda: AutoTokenizer.from_pretrained(model_id))
model = lazy_object_proxy.Proxy(
    lambda: AutoModelForCausalLM.from_pretrained(model_id).to(device)
)
login_done = False


def ensure_login():
    """Makes sure that we're logged into HuggingFace Hub so that we can
    download the LLM (which requires to approve a license)."""

    global login_done

    if not login_done:
        login(token=environ["HUGGINGFACE_TOKEN"])
        login_done = True</code></pre><p>A bunch of things to unpack:</p><ul><li><p>Everything is wrapped in a <a href="https://pypi.org/project/lazy-object-proxy/">lazy_object_proxy</a>, which avoids to blow up the CPU and RAM at moment the module is imported. It will wait that the function is called a first time for that. You&#8217;ll thank me later.</p></li><li><p>We create an ensure_login() function which allows subsequent functions to make sure that we&#8217;re logged into huggingface_hub, but also does it only once to avoid having to do this every time we call the AI.</p></li><li><p>There is a conditional detection of CUDA to enable it or not depending on the availability. You guys tell me if it works, I&#8217;m an idiot who didn&#8217;t check his GPU&#8217;s compatibility before buying it.</p></li></ul><h3>Communicate with Gemma</h3><p>You&#8217;ve probably noted the name of the model, <code>google/gemma-2b-it</code>.</p><ul><li><p>The &#8220;2b&#8221; indicates the size of the model. I&#8217;m using this one and not the bigger one because it uses a lot less resources and can realistically be used on a CPU while the other one cannot.</p></li><li><p>The "it&#8221; tells you that it has been trained for chat-like interactions.</p></li></ul><p>So how do you get anything about this chat training? It means that your prompt has to follow this structure:</p><pre><code>&lt;start_of_turn&gt;user
How does the brain work?&lt;end_of_turn&gt;
&lt;start_of_turn&gt;model</code></pre><p>It indicates to the model the alternance between human and model speakers. Sadly, it does not have a system prompt to also guide the LLM outside of this, but we&#8217;ll go around that.</p><p>The idea is to use it the following way:</p><pre><code>def ask_gemma(instruction: str, this_input: str, max_tokens: int = 1000) -&gt; str:
    ensure_login()

    chat = [
        {
            "role": "user",
            "content": f"# Instructions\n{instruction}\n# Input\n{this_input}",
        },
    ]

    prompt = tokenizer.apply_chat_template(
        chat,
        tokenize=False,
        add_generation_prompt=True,
    )
    inputs = tokenizer.encode(
        prompt,
        add_special_tokens=True,
        return_tensors="pt",
    )
    outputs = model.generate(
        input_ids=inputs.to(model.device),
        max_new_tokens=max_tokens,
    )

    convo_raw = tokenizer.decode(outputs[0])
    convo: Sequence[Dict] = parser.parse(convo_raw)  # noqa

    return convo[-1]["content"]</code></pre><p>What you see here is that we&#8217;re using the tools from the transformers lib to generate the chat template prompt and give it to the LLM. Then when it runs, you receive a response that contains both the question and the answer from the bot, and&#8230; It becomes a bit confusing.</p><p>To be honest I&#8217;m not entirely sure how I&#8217;m supposed to parse this or if there are utilities in the transformers lib (I didn&#8217;t find them), so I&#8217;ve written my own parser (which you see used in the code above).</p><p>If you&#8217;ve outgrown your fear of regular expressions you may outgrow your fear of parsers as well. It&#8217;s relatively easy to write using the <a href="https://lark-parser.readthedocs.io/en/stable/">Lark package</a>. It&#8217;s not the scope of this article, just <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/ai/gemma.py#L67">check the grammar</a> if you&#8217;re interested. What matters is that we&#8217;ve got a parser!</p><p>Another thing is that you&#8217;ve noticed how there are two important parameters:</p><ul><li><p>instruction &#8212; Corresponds to the system prompt, tells the bot what to do</p></li><li><p>this_input &#8212; The user input</p></li></ul><p>Since there is no management of system prompt in this fine-tuning, I&#8217;m just bulding a prompt from those two and hoping that the LLM picks it up (it does).</p><p>At this point we have a function that runs the LLM locally on your CPU/GPU. Pretty neat!</p><h2>Getting the email&#8217;s text</h2><p>Emails might be the oldest and most inconsistent standard in the Internet world. Their encoding is super confusing and while Python has a built-in library that implements all the heavy lifting, it really comes as a kit that you&#8217;ve got to assemble yourself (without the instructions).</p><p>The strategy is as follows:</p><ol><li><p>Go through the different &#8220;parts&#8221; of the email, looking either for a plain text or a HTML attachment. With a preference for the HTML attachment, because sometimes you will find a plain text attachment that turns out to be bullshit, so sadly only the HTML is reliable.</p></li><li><p>Because the HTML is pretty fat, if that&#8217;s what we&#8217;re going for we&#8217;ll make sure to convert it into Markdown. This will greatly reduce the amount of tokens and absolutely reduce the complexity of understanding the message for the LLM.</p></li></ol><p>This is all the job of the <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/parser.py#L80">parse_email()</a> function, which I&#8217;m not going to detail because it would be off-topic. What you need to know is that it outputs the email in a simplified text format which looks like:</p><pre><code>From: foo@bar.com
To: someone@example.com
Date: 2024-02-23 20:12:00 +0100
Subject: Some email

Blah blah blah this is the content of the email</code></pre><p>It&#8217;s something we can easily give to our LLM.</p><h2>Plain text to JSON</h2><p>Now the useful part. The core of this project is to convert plain text into JSON, isn&#8217;t it? <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/ai/__init__.py#L22">Let&#8217;s do that</a>!</p><pre><code>def parse_to_json(
    prompt: str, text: str, schema: Any, attempts: int = 3
) -&gt; Optional[Any]:
    for _ in range(attempts):
        parsed_raw = ask(prompt, text)
        parsed_raw = MD_START.sub("", parsed_raw)
        parsed_raw = MD_END.sub("", parsed_raw)
        try:
            parsed = yaml.safe_load(parsed_raw)
            jsonschema.validate(parsed, schema)
        except (yaml.YAMLError, jsonschema.ValidationError):
            pass
        else:
            return parsed</code></pre><p>What do we see here:</p><ul><li><p>First we clean up the model for any Markdown enclosing. <em>Sometimes</em> chat-tuned models like to put YAML within <code>```yaml</code> quotes. We make sure to remove it if this happens.</p></li><li><p>Then we try to load the YAML data. Why YAML and not JSON? Easy: JSON is a sub-set of YAML so if the model decides to output JSON it will still work, but on the other hand YAML is more permissive and uses less tokens than JSON. So it&#8217;s both safer and more economic to use.</p></li><li><p>If all went well, we validate the parsed structure against the provided JSON schema. This ensures that the output corresponds to the constraints that we need to work with.</p></li><li><p>And if not or if the validation fails, we try again. Most LLMs will not strictly always have the same output for a given input so it doesn&#8217;t hurt to try another time to see if it&#8217;s still broken.</p></li></ul><h3>Prompting</h3><p>In order to parse the different elements, we&#8217;ll use a <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/prompts.py">prompt library</a>. For each prompt, we associate a JSON schema which helps validating the output.</p><p>I&#8217;m not going to go through every single prompt because if you&#8217;re human you can probably understand them but I&#8217;m just going to explain <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/prompts.py#L12">the one I use to classify emails</a> because it&#8217;s the hard one.</p><p>My goal here is to determine the probability of each email type by asking explicitly the LLM to give that probability according to different factors that I give him. The idea is that you can then easily pick the email type by checking which is the category with the highest probability. We rely on the LLM&#8217;s feelings but we&#8217;re using hard Python algorithms to take the decision.</p><p>The prompt goes as follows:</p><pre><code>Take a deep breath.

You will analyze an email. For this email you need to determine the
likeliness that this email belongs to a specific category. This works
with a score system. For each category you MUST give a score of 0 if
you are sure that it's not from that category, a score of 1 if you are
sure or a number between 0 or 1 that reflects how much you want to
give that category to the email.

The categories are:
    - Commercial is a prospective email.
    - Bill is an invoice or a bill for a sold service or product.
    - Conversation is a regular conversation between humans.

Here are elements to look for in an email. For each element, if I tell 
you +X then consider that it's adding points to that aspect and -X is 
removing points.

Has few sentences +bill -commercial
Has a total price +bill
Has a list of items sold +bill
Has "bill", "invoice", "order confirmation" or any synonym in the Subject +bill -commercial -conversation
Presents several product benefits +commercial -bill
Is structured in a Hello/Message/Signature way +conversation -bill
Different signatures and quoted mails +conversation -bill -commercial

Now return the following YAML:

bill: x
commercial: x
conversation: x

You need to replace "x" by the score. If you want to give a score of
1 to two or more categories, you need to think harder to make the
difference.

Make sure that the output is pure YAML, not wrapped in Markdown, no sentences.</code></pre><p>You can see the structure:</p><ol><li><p>The LLM receives a general purpose</p></li><li><p>Then I explain the categories</p></li><li><p>Then I give the different factors for the different categories so that the LLM knows what to look for (it&#8217;s really not working if you don&#8217;t do this)</p></li><li><p>Then I give the YAML schema at the end. If the schema is too high in the prompt the LLM tends to forget about it</p></li><li><p>And then some banalities about the output to avoid getting stuff like &#8220;Of course, here is your YAML&#8221;, which would screw the parsing</p></li></ol><p>This is matched up by a JSON schema:</p><pre><code>{
    "type": "object",
    "properties": {
        "commercial": {"type": "number", "minimum": 0, "maximum": 1},
        "bill": {"type": "number", "minimum": 0, "maximum": 1},
        "conversation": {"type": "number", "minimum": 0, "maximum": 1},
    },
    "required": ["commercial", "bill", "conversation"],
}</code></pre><p>With this strategy, I&#8217;ve written 4 prompts:</p><ul><li><p>The one you&#8217;ve just seen to determine the email&#8217;s type</p></li><li><p>If it&#8217;s a commercial email, extract the name of the product and the USP</p></li><li><p>If it&#8217;s a bill, extract the total price and the purchased items</p></li><li><p>If it&#8217;s a conversation, make a summary of the conversation</p></li></ul><h2>Deciding</h2><p>And all this culminates into the <a href="https://github.com/Xowap/semmail/blob/e305aee3a3e523463de66390b8ece765b6a08ae8/src/semmail/parser.py#L111">interpret_email()</a> function.</p><pre><code>def interpret_email(email: bytes) -&gt; Any:
    """Uses a first round of LLM in order to determine the type of message,
    then proceeds to using a specific prompt for that type in order to parse
    the email into a JSON output."""

    parsed_email = parse_email(email)

    email_type_proba = parse_to_json(
        DETERMINE_TYPE.prompt,
        parsed_email,
        DETERMINE_TYPE.schema,
    )

    email_type = max(email_type_proba.items(), key=lambda p: p[1])[0]
    extra = {}

    if email_type == "commercial":
        extra["commercial"] = parse_to_json(
            COMMERCIAL_INFO.prompt,
            parsed_email,
            COMMERCIAL_INFO.schema,
        )
    elif email_type == "bill":
        extra["bill"] = parse_to_json(
            BILL_INFO.prompt,
            parsed_email,
            BILL_INFO.schema,
        )
    elif email_type == "conversation":
        extra["conversation"] = parse_to_json(
            CONVERSATION_INFO.prompt,
            parsed_email,
            CONVERSATION_INFO.schema,
        )

    return dict(
        email_type=dict(
            chosen=email_type,
            proba=email_type_proba,
        ),
        **extra,
    )</code></pre><p>Which is very simple:</p><ul><li><p>First we determine the email type, which we get as a JSON object</p></li><li><p>And then we use one of the three parsers to get the extra information relative to this type</p></li><li><p>And finally we output a JSON with the extracted information and the decision-making values that we&#8217;ve used</p></li></ul><p>So if I take my latest Amazon purchase, I&#8217;m getting the following output:</p><pre><code>{
  "bill": {
    "bought": [
      {
        "label": "L'investisseur eclaire: Cultiver son...",
        "price": [
          37.46,
          "EUR"
        ]
      }
    ],
    "total": [
      43.72,
      "EUR"
    ]
  },
  "email_type": {
    "chosen": "bill",
    "proba": {
      "bill": 1,
      "commercial": 0.2,
      "conversation": 0
    }
  }
}</code></pre><p>Hooray! It worked!</p><h2>Conclusion</h2><p>I&#8217;ve showcased two things in this article:</p><ul><li><p>Using extremely small boilerplate code and pretty conventional tools, I can easily leverage LLMs to parse generic content into usable JSON. It&#8217;s something that was completely unthinkable a few months ago!</p></li><li><p>And I can do so using a local LLM that even runs on &#8220;commodity&#8221; hardware (be sure to have 10 Gio of RAM before starting the proejct, or you&#8217;ll see how fast your computer can freeze)</p></li></ul><p>This is an exciting time because long-standing problems are finally getting solved. In a near future you can expect to see every single tool out there getting <em>a lot</em> smarter when it comes to understanding human text.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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[Stop doing these mistakes with your caching proxy]]></title><description><![CDATA[How to get sub-10ms response times, real time content expiration, automatic compression all while offloading your backends. Enter the power of RFC 9110 and discover the underdog of reverse proxies.]]></description><link>https://www.baby-cto.com/p/mistakes-with-caching-proxy-rfc-9110</link><guid isPermaLink="false">https://www.baby-cto.com/p/mistakes-with-caching-proxy-rfc-9110</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sat, 17 Feb 2024 20:09:43 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b2bcb6e6-f334-4455-ac7b-ccd4be64714e_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You got yourself a website with static-ish content which takes a lot of time to generate and you are looking to make it faster. The obvious solution is caching, but that is a surprisingly intricate and delicate topic when even the slightest bit of interaction starts to happen. Moreover you would probably be happy if your cache could refresh your content automatically when you hit &#8220;Publish&#8221; in your CMS. And finally, as state you have different interaction points in your website so you can&#8217;t exactly turn towards static website generators.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/mistakes-with-caching-proxy-rfc-9110?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.baby-cto.com/p/mistakes-with-caching-proxy-rfc-9110?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>Your typical stack</h2><p>The application that you are going to develop through this article is a very simple <a href="https://flask.palletsprojects.com/">Flask</a> application designed only to explore the concepts that we&#8217;re introducing without getting the noise of a more complex setup.</p><p>However these concepts can apply to many different configurations. Specifically, if you are reading this in 2024 chances are that you are already running a given amount of <em>headless</em> CMS&#8217;:</p><ul><li><p>A back-end/API which runs whichever CMS that has a &#8220;headless mode&#8221;. This author would recommend <a href="https://wagtail.org/">Wagtail</a> but the list of such beasts is growing extremely long these days.</p></li><li><p>A front-end meta-framework which renders a first version of your content on the server side and then hydrates the HTML within the client to give full interactivity to the pages. You could use <a href="https://kit.svelte.dev/">SvelteKit</a>, <a href="https://nuxt.com/">Nuxt</a>, <a href="https://astro.build/">Astro</a> or <a href="https://nextjs.org/">Next.js</a> for example.</p></li></ul><p>If you were to do so, you essentially need to consider your front-end as a proxy on top of your API, which performs a JSON to HTML encoding transformation. This suggests that if you implement the RFC 9110 in your front-end, the solution that you&#8217;re going to discover below should still apply. Maybe the topic for a future article!</p><h2>A bit of HTTP</h2><p>That&#8217;s where lies the secret that the reverse proxying industry doesn&#8217;t want you to learn. HTTP presents numerous cache modes &#8212; in particular through the <code>Cache-Control</code> header &#8212; but oftentimes you&#8217;ll end up with a solution that is time-based. You tell the cache &#8220;please keep this for an hour&#8221; and it will do so. Hell if you updated the content, it will expire when it will. Of course there are techniques to alleviate this issue with background revalidation for example but in addition to the time-based inconvenience, the higher the refesh rate the higher the load on your back-end.</p><p>On the other hand, an extremely easy way to keep the cache up-to-date is through conditional validation and in particular the use of the <code>ETag</code> header. The conversation looks like this:</p><ul><li><p>Client: give me /foo</p></li><li><p>Server: here&#8217;s /foo, with ETag 1234</p></li><li><p>Client: give me /foo if it is not 1234 anymore</p></li><li><p>Server: not changed, use your cache</p></li></ul><p>Simply checking that the value of the ETag didn&#8217;t change is incredibly cheap to perform while also making sure that your content always stays up-to-date. For example you can imagine putting in this header something built upon the version of the page in your CMS. As soon as something new is published, all the caches will be renewed.</p><blockquote><p><em>Story time</em>: yours truly used to work on a private social network that used to have lots of interactive widgets which relied heavily on polling, as websockets were not invented yet. The polling as wearing the server down at a crazy rate, but implementing an ETag-based cache that was solely relying on the browser cache made an utterly dramatic improvement on the server load.</p></blockquote><p>Obviously this is far from being the only valid caching strategy out there but if your target audience is geographically close enough and you want to rely only on standard HTTP mechanisms instead of implementing proprietary logics using mystical lines in your proxy&#8217;s configuration DSL, you this is a fairly efficient solution which will bring you sub-10ms response generation time.</p><h2>The mighty RFC 9110</h2><p>The governing RFC for what you are trying to accomplish here is the <a href="https://www.rfc-editor.org/rfc/rfc9110">RFC 9110</a>. To summarize the interesting parts, a cached resource has different states:</p><ul><li><p>Fresh &#8212; The content is in cache and we know it&#8217;s still valid</p></li><li><p>Stale &#8212; The content is in cache but we need to re-validate it</p></li><li><p>Missing &#8212; No concent in cache, must do the request</p></li></ul><p>When putting an ETag on a resource, it will automatically cache it as stale and re-validate it using <a href="https://www.rfc-editor.org/rfc/rfc9110#name-if-none-match">If-None-Match</a>, which is the mechanic described above. On the server-side it&#8217;s very easy, in pseudo code:</p><pre><code>if 'if-none-match' in headers:
    if headers['if-none-match'] == latest_etag_for_route():
        return 304

return normal_response()</code></pre><p>However at the cache level it seems to be more tricky. It&#8217;s easy to set your proxy to forward the client&#8217;s <code>If-None-Match</code> (INM) header, but when you start to consider different possibilities it&#8217;s not so obvious anymore:</p><ul><li><p>What if the client doesn&#8217;t say INM but the proxy has this resource in cache?</p></li><li><p>What if the client&#8217;s INM mismatches the one in cache?</p></li><li><p>What if the client has an INM but the proxy has nothing in cache?</p></li><li><p>And so forth <em>ad nauseam</em></p></li></ul><p>This mechanic being so tricky, this author attempted to implement it with many different caching proxies without success:</p><ul><li><p><code>nginx</code> &#8212; Has many options which could probably lead up to correctly implementing RFC 9110 but it is dishearting of complexity and uncertainty</p></li><li><p><code>varnish</code> &#8212; Does the job <a href="https://serverfault.com/questions/1153078/etag-based-content-revalidation">with a bit of tweaking</a> but will make your life hard if you have cookies</p></li><li><p><code>squid</code> &#8212; Fails miserably</p></li><li><p><code>traefik</code> &#8212; Maybe the enterprise version has the feature but the license is just prohibitive</p></li><li><p><code>caddy</code> &#8212; Does not actually have a cache</p></li><li><p>Apache&#8217;s <code>httpd</code> &#8212; Honestly maybe but I could not figure it out</p></li></ul><p>You will probably be wondering at this stage which solution can you then use, as the most popular solutions from today and yesterday are all listed here. Turns out that another solution, which was barely even on the radar, has the following table in its documentation:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NoeC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NoeC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 424w, https://substackcdn.com/image/fetch/$s_!NoeC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 848w, https://substackcdn.com/image/fetch/$s_!NoeC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 1272w, https://substackcdn.com/image/fetch/$s_!NoeC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NoeC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png" width="1130" height="515" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:515,&quot;width&quot;:1130,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66362,&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_!NoeC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 424w, https://substackcdn.com/image/fetch/$s_!NoeC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 848w, https://substackcdn.com/image/fetch/$s_!NoeC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 1272w, https://substackcdn.com/image/fetch/$s_!NoeC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff54f0012-08ac-4f7d-aa82-67156335b77d_1130x515.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is an extract from the <a href="https://docs.trafficserver.apache.org/admin-guide/storage/index.en.html#if-modified-since-if-none-match">Apache Traffic Server</a> documentation. By-product of an acquisition from Yahoo which subsequently open-sourced it in 2009, ATS probably has one of the most unfriendly configuration syntax that you&#8217;ll ever see &#8212; especially if you look at the default files in the Debian package &#8212; which may make you want to give up immediately.</p><div class="poll-embed" data-attrs="{&quot;id&quot;:147600}" data-component-name="PollToDOM"></div><p>Beyond the initial intimidating look, it&#8217;s actually a strong contender:</p><ul><li><p>It is used by massive CDN companies, so while it&#8217;s going to be hard to compare it directly to something like nginx you can imagine that it is at least at the same level of performance and feature.</p></li><li><p>It is explicitly a proxy and specializes in doing so. You won&#8217;t be configuring a plugin to do proxying, it is the core feature. It changes radically the ease of configuration.</p></li><li><p>Last but not least, it implements RFC 9110 correctly enough by default so that you can configure the cache behavior through standard HTTP headers and not be too surprised about the actual behavior.</p></li></ul><p>You can dig deeper into ATS through <a href="https://www.youtube.com/watch?v=RNTw7jZwlKQ">this video</a>, but you will be reading about the important bits of configuration right below.</p><h2>The project itself</h2><p>The goal of today is to demonstrate how you can use ETags to cache and expire your content on a proxy. To that extent you&#8217;ll be implementing the following page:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vTIu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vTIu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 424w, https://substackcdn.com/image/fetch/$s_!vTIu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 848w, https://substackcdn.com/image/fetch/$s_!vTIu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 1272w, https://substackcdn.com/image/fetch/$s_!vTIu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vTIu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png" width="394" height="139" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:139,&quot;width&quot;:394,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14337,&quot;alt&quot;:&quot;The example app displays the \&quot;Expected ETag\&quot; value, a \&quot;Random String\&quot; and a button to change the ETag.&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="The example app displays the &quot;Expected ETag&quot; value, a &quot;Random String&quot; and a button to change the ETag." title="The example app displays the &quot;Expected ETag&quot; value, a &quot;Random String&quot; and a button to change the ETag." srcset="https://substackcdn.com/image/fetch/$s_!vTIu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 424w, https://substackcdn.com/image/fetch/$s_!vTIu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 848w, https://substackcdn.com/image/fetch/$s_!vTIu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 1272w, https://substackcdn.com/image/fetch/$s_!vTIu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7eee4c66-5ec3-42ec-964d-feee1ed867b2_394x139.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Our demo of the ETag caching</figcaption></figure></div><p>You can control that the ETag and caching mechanisms work properly using this page:</p><ul><li><p>If the expected ETag doesn&#8217;t change, it means that the server is indeed consistent with its ETag</p></li><li><p>If the random string changes it means that the page has been re-generated while if it stays the same it means that the page came from the cache</p></li></ul><p>The rest of this article will contain extracts of code, but the whole project can be <a href="https://github.com/Xowap/cache-cache">found on GitHub</a> and shall serve a reference.</p><h3>View logic</h3><p>While there are probably many ways to deal with ETag that are nicer than this (for example in Django there is a super-easy etag decorator), here is the logic you need to implement an ETag/If-None-Match cache:</p><pre><code>from flask import Flask, make_response, redirect, render_template, request, url_for

from .etag import *

app = Flask(__name__)


@app.route("/", methods=["GET", "POST"])
def etag_demo():
    """This view displays a simple template that informs the user about the
    current ETag value and a random string. This allows to demonstrate how
    ETag works (cache gets refreshed when ETag changes) and to test if caching
    works (if the cache works, the random string shouldn't change)."""

    if request.method == "POST":
        new_etag = generate_random_string()
        set_etag(new_etag)
        return redirect(url_for("etag_demo"))

    current_etag = get_or_set_etag()

    if current_etag == extract_etag(request.headers.get("If-None-Match", "")):
        response = make_response("", 304)
    else:
        response = make_response(
            render_template(
                "etag.html",
                etag=current_etag,
                random_string=generate_random_string(),
            )
        )

    # We put s-maxage=0 instead of no-cache because somehow this incites
    # caching proxy better to store the request into cache
    response.headers["Cache-Control"] = "public, must-revalidate, s-maxage=0"
    response.headers["ETag"] = f'W/"{current_etag}"'

    return response


if __name__ == "__main__":
    app.run(debug=True)</code></pre><p>A bunch of helpers are abstracted away in the <a href="https://github.com/Xowap/cache-cache/blob/master/backend/src/cache_cache/etag.py">etag.py file</a>, but the logic is basically exactly the same as the one listed right above, with simply the addition of rendering the template.</p><p>You can checkout the project <a href="https://github.com/Xowap/cache-cache">from GitHub</a> and run the backend:</p><pre><code>git clone git@github.com:Xowap/cache-cache.git
cd cache-cache/backend
poetry install
make serve</code></pre><p>This will start the server on <a href="http://localhost:5000/">http://localhost:5000/</a>, which you can now visit. You can in theory see the page, refresh it as many times as you want without seeing the random string change and then click the button to change the ETag. That&#8217;s all because you are doing this from the same browser but if you open another browser you will get a completely different output &#8212; albeite the output being consistent within one browser.</p><p>The next steps aim to configure a shared cache in front of this backend which will allow to cache the same resource for different users at the same time.</p><h2>Core configuration</h2><p>Most likely these days you will be deploying in a Kubernetes or at least dockerized environment. However ATS has surprisingly few options available for Docker, leading yours truely to create a <a href="https://hub.docker.com/r/xowap/trafficserver">base Docker image</a> which you can use and which will be the base of this configuration. It is based on the standard Debian package, with a bit of wrapping to help extrapolating the configuration from environment variables. Also it offers a simpler way to fill up the infamous <code>records.config</code> file.</p><p>The file structure you need to create is the following:</p><pre><code>&#9500;&#9472;&#9472; Dockerfile
&#9492;&#9472;&#9472; etc
    &#9500;&#9472;&#9472; compress.config
    &#9500;&#9472;&#9472; header_rewrite.config
    &#9500;&#9472;&#9472; logging.yaml
    &#9500;&#9472;&#9472; plugin.config
    &#9500;&#9472;&#9472; records.config.yaml
    &#9492;&#9472;&#9472; remap.tpl.config</code></pre><h3>Base configuration</h3><p>It looks complex but in truth each file manages one specific and simple aspect of the configuration. Let&#8217;s start with the two only files that you really need to edit to get started:</p><p>First is the <code>records.config</code>, which here is <code>records.config.yaml</code> thanks to the <a href="https://hub.docker.com/r/xowap/trafficserver">Docker image&#8217;s wrapper</a> which will do the conversion from friendly YAML to whatever the ATS DSL is.</p><pre><code>proxy:
    config:
        admin:
            user_id: trafficserver
        log:
            logging_enabled: 3
        http:
            server_ports: "9000"
            connect_attempts_timeout: 30
            normalize_ae: 2
        reverse_proxy:
            enabled: true
        url_remap:
            remap_required: true
            pristine_host_hdr: true</code></pre><p>At the core, we&#8217;ve got the two most essential lines:</p><ul><li><p><code>reverse_proxy.enabled</code> &#8212; makes sure to work in reverse proxy mode</p></li><li><p><code>remap_required</code> &#8212; disables the forward proxy mode</p></li></ul><p>Then a bunch of stuff that will be useful now or later:</p><ul><li><p><code>user_id</code> &#8212; required to run it as trafficserver user (which is the default on Debian)</p></li><li><p><code>logging_enabled</code> &#8212; you&#8217;ll see the logging config later</p></li><li><p><code>server_ports</code> &#8212; put there whichever port(s) you fancy</p></li><li><p><code>connect_attempts_timeout</code> &#8212; always have a timeout, this sounds reasonable</p></li><li><p><code>normalize_ae</code> &#8212; normalization of <code>Accept-Encoding</code> HTTP header which optimizes the caching of resources when <code>Accept-Encoding</code> is part of <code>Vary</code> (the value 2 is to have both gzip and brotli supported)</p></li><li><p><code>pristine_host_hdr</code> &#8212; just forward the initial hostname to the services behind, makes your life easier</p></li></ul><p>Second is the <code>remap.config</code>, whose job is basically to route your URLs to your web servers. You will however write the <code>remap.tpl.config</code> file, which leverage&#8217;s the Docker image&#8217;s wrapper that can inject environment variables into it:</p><pre><code>map / {{ BACKEND_URL }}/</code></pre><p>Nothing fancy here. You are just redirecting all traffic to BACKEND_URL, which is an environment variable that you will have to feed into your Docker container.</p><p>You could stop there in the configuration as this is already a working reverse caching proxy routing to your app! But you&#8217;ll see that there are a few more goodies to be found.</p><h3>Compression</h3><p>It is often advised to use compression of all the text assets<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> for performance reasons, and indeed a long HTML page can be much faster to download if encoded in Brotli for example.</p><p>The web has commonly 3 compression algorithms:</p><ul><li><p>gzip &#8212; The fastest, most commonly supported and not necessarily the most efficient but it is already doing a good job</p></li><li><p>brotli &#8212; The newest kid on the block, made by Google, outperforms gzip by far in compression rate but is obviously much more expensive to encode</p></li><li><p>deflate &#8212; Too similar to gzip to be interetsing</p></li></ul><p>When making a HTTP request, a client will specify through the Accept-Encoding header which of those algorithms it supports. Typically, all the major browsers support all of them.</p><p>However not all servers support compression &#8212; and even if they do, the support is often complex or straight out causing bugs. It is typically handled through middlewares that will modify the rendered response on-the-fly in a more or less accurate and standard-aware way. Not to mention the cost and complexity of getting those CPU-bound algorithms running in Python, Node or your favorite server-side interpreted language.</p><p>Because of that, you will have a much more consistent result if you just rely on your reverse proxy for this. It is a popular <a href="https://developers.cloudflare.com/speed/optimization/content/brotli/">feature of Cloudflare</a>, or if you want it with nginx you&#8217;re gonna have to go with <a href="https://github.com/google/ngx_brotli">an experimental plugin</a> or with the <a href="https://docs.nginx.com/nginx/admin-guide/dynamic-modules/brotli/">paid version</a> of nginx.</p><p>Fortunately it&#8217;s already embedded in ATS, which is able for each resource that you cache to generate different <a href="https://docs.trafficserver.apache.org/en/9.0.x/appendices/glossary.en.html#term-alternate">alternates</a> for different compressions, including gzip and brotli. This all happens on-the-fly, and the cache is able to convert one encoding to the other without fetching the original resource again.</p><p>Here&#8217;s what you need to do in order to perform this magic.</p><p>First, edit the plugin.config file to put the following line:</p><pre><code>compress.so /etc/trafficserver/compress.config</code></pre><p>You&#8217;re telling to load the compress.so module with the compress.config file as configuration. You could enable the plugin just for some routes with a different configuration for example, but for this exemple it will just be global.</p><p>In compress.config, put the following:</p><pre><code>remove-accept-encoding true
supported-algorithms br,gzip
minimum-content-length 0

compressible-content-type text/*
compressible-content-type *font*
compressible-content-type *javascript
compressible-content-type *json
compressible-content-type *ml;*
compressible-content-type *mpegURL
compressible-content-type *mpegurl
compressible-content-type *otf
compressible-content-type *ttf
compressible-content-type *type
compressible-content-type *xml
compressible-content-type application/eot
compressible-content-type application/pkix-crl
compressible-content-type application/x-httpd-cgi
compressible-content-type application/x-perl
compressible-content-type application/json
compressible-content-type image/vnd.microsoft.icon
compressible-content-type image/x-icon</code></pre><p>You can interpret the options the following way:</p><ul><li><p><code>remove-accept-encoding</code> &#8212; don&#8217;t tell the server that the client accepts different encodings as it doesn&#8217;t really matter, the work is going to be done on the proxy side</p></li><li><p><code>supported-algorithm</code> &#8212; allow brotli and gzip, which as stated before are the two interesting algorithms. In order for this to work, you&#8217;ll observe that <code>normalize_ae</code> from <code>records.config</code> is set to 2, because otherwise the normalization process would just systematically strip brotli from the list of candidates</p></li><li><p><code>minimum-content-length</code> &#8212; no limits on the content size, as the default value is made for gzip and brotli is more efficient</p></li><li><p><code>compress-content-type</code> &#8212; a reasonable list of content types that we&#8217;d like to compress before sending away, adjust for your needs</p></li></ul><p>With this configured, you get top-of-the-line compression basically effortlessly and for free. Keep an eye on your CPU though, because this might hurt of abused: if required you can disable brotli for routes that have lots of throughput and don&#8217;t stay in cache as gzip still has significant gains over the absence of compression while being much faster to compress.</p><h3>Logging</h3><p>You probably want at least some logs, to have a glance at what is going through your server. You will be the one deciding what to put in there, following the <a href="https://docs.trafficserver.apache.org/en/9.0.x/admin-guide/logging/formatting.en.html">fairly extensive documentation</a>, but let&#8217;s consider that since you&#8217;re dealing with a Docker service you&#8217;ll want to output everything to stdout.</p><p>You can start with the following logging.yaml file:</p><pre><code>logging:
    formats:
        - name: access
          format: '%&lt;cqtn&gt; %&lt;cqhm&gt; %&lt;cluc&gt; -&gt; %&lt;shn&gt;:%&lt;nhp&gt; %&lt;crc&gt;'

    logs:
        - mode: ascii
          filename: stdout
          format: access</code></pre><p>That&#8217;s super basic but you can extend it as much as you want!</p><h3>Headers</h3><p>A last thing that you&#8217;ll probably want to do is to add some meta information to the response header in order to know the caching status. Add to your plugins:</p><pre><code>header_rewrite.so /etc/trafficserver/header_rewrite.config</code></pre><p>And then put this content in <code>header_rewrite.config</code>:</p><pre><code>add-header X-Cache %{CACHE}</code></pre><p>Thanks to this you can know when navigating to your project which pages come from the cache and which don&#8217;t.</p><h2>Run it all</h2><p>Now is the time to test the whole solution. Start the whole thing using Docker Compose:</p><pre><code>docker-compose up --build</code></pre><p>When it&#8217;s started, give a try to <a href="http://localhost:9000/">http://localhost:9000/</a>. The same thing as with the stand-alone backend should be displayed and if you try it from a single browser you should see exactly the same result.</p><p>The interesting part is when you open with a different browser, or when you disable the cache in your current browser. You&#8217;ll notice that the random string stays consistent between different browser instances. It means that indeed, the cache is shared between all browser instances. Mission accomplished!</p><p>To convince yourself even further, you can inspect the X-Cache header from your HTTP requests. If you just refresh the page without changing the ETag, whether your receive a 200 or a 304 on the client &#8212; depending on  your browser&#8217;s cache status &#8212; you will see in the header that you had a cache hit, which will be confirmed by the backend&#8217;s access log which will only show 304 responses.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Baby CTO! 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>Wrap up</h2><p>You have explored throughout this article the power of the RFC 9110 and of respecting it. It allows to express advanced indications regarding the caching of content, its re-validation in real time and its transformation.</p><p>Using this tactically can greatly reduce the load on a backend server by getting most of the request results from the cache instead of implementing proprietary logics through middlewares and obscure configuration mechanisms.</p><p>This however outlines that few reverse proxies actually implement all the necessary tools. Which puts the light on Apache Traffic Server, an extremely powerful piece of software quite generally ignored by the community but which provides out of the box all the latest goodies from your dreams, with a specialized and simple configuration &#8212; if you go beyond the initial intimidating aspect of the configuration files.</p><p>And while the respect of RFC 9110 applies to the reverse proxy, it can also be a powerful tool for you to leverage in a typical headless CMS setup. This remains a topic to be explored further in a new article! </p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Compression and encryption are fundamentally incompatible notions as they try to achieve strictly opposite goals. Compression will try to condense the entropy of your text while encryption tries to drown it into as much noise as possible. As such, compressing a secret and serving it through HTTPS will lead to security issues such as <a href="https://en.wikipedia.org/wiki/BREACH">BREACH</a>. Just make sure to never ever compress a secret.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Jobs for LLMs and how to survive the robotic uprising]]></title><description><![CDATA[While absolutely mind-blowing, LLMs are a far cry from a real human beings. There are no silver bullets and like any technology it's time to review what are its strengths and weaknesses.]]></description><link>https://www.baby-cto.com/p/jobs-for-llms-and-how-to-survive</link><guid isPermaLink="false">https://www.baby-cto.com/p/jobs-for-llms-and-how-to-survive</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sun, 11 Feb 2024 19:37:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/aefc7024-dbb6-42e9-9904-d75dc411bcd8_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>About 2 years ago, some circles started to be seriously heated about a &#8220;GPT&#8221; thing so I managed to get myself invited to try it out. I was expecting something mildly better than other moderately impressive tech like <a href="https://en.wikipedia.org/wiki/BERT_(language_model)">BERT</a> or what <a href="https://deeppavlov.ai/">DeepPavlov</a> could do at the time. Instead I ended up using it every single day ever since for everything ranging from planning my holidays, writing code or replying to administrative emails for me.</p><p>And while utterly neutral research centers like &#8220;Microsoft Research&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> wrote the now-famous &#8220;<a href="https://arxiv.org/pdf/2303.12712.pdf">Sparks of AGI</a>&#8221; paper claming that most jobs well be replaced by AI, we can also see studies from the MIT (and IBM) that wonder <a href="https://futuretech-site.s3.us-east-2.amazonaws.com/2024-01-18+Beyond_AI_Exposure.pdf">if AI is such a cost-effective solution</a>. Turns out that maybe&#8230; not so much.</p><p>This begs the question: what is it smart to outsource to LLMs and what is not?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/jobs-for-llms-and-how-to-survive?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.baby-cto.com/p/jobs-for-llms-and-how-to-survive?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>Transforming stuff</h2><p>You&#8217;ve probably already read how LLMs work and how they use the transformer architecture and huge amounts of data to train over a billion 300 million trillion 300 million parameters. So that&#8217;s not what we&#8217;re going to talk about.</p><p>LLMs are essentially good at taking a text, transforming it into its raw essence, transfomring it and then outputing it in a different form. For example, I asked GPT-4:</p><blockquote><p>Please parse the following text into semantic JSON, and output only JSON: Yeah so i've been grocery shopping and there was no more fresh milk but still some regular milk so I took 1L of this for 2&#8364; and then I wanted to buy cereals but I figured it's not good for my diet so I didn't and I got 3kg of broccoli for 5&#8364;</p></blockquote><p>The answer is:</p><pre><code>{
  "activities": [
    {
      "activity": "grocery shopping",
      "details": [
        {
          "item": "milk",
          "type": "regular",
          "quantity": "1L",
          "price": "2&#8364;"
        },
        {
          "item": "cereals",
          "decision": "not purchased",
          "reason": "not good for diet"
        },
        {
          "item": "broccoli",
          "quantity": "3kg",
          "price": "5&#8364;"
        }
      ]
    }
  ]
}
</code></pre><p>You can see exactly the same story translated into JSON. And it makes sense!</p><p>The same goes for translating to foreign languages. For example I asked GPT-4 to translate &#8220;You fucking suck&#8221; in different languages, here&#8217;s what I&#8217;m getting:</p><ul><li><p><strong>Polite French</strong>: Votre performance est tr&#232;s insuffisante.</p></li><li><p><strong>Slang French</strong>: Tu es nul</p></li><li><p><strong>Legalese</strong>: The manner in which you perform is utterly unsatisfactory.</p></li></ul><p>Obviously it was a bit challenging to get a response as those LLMs all refuse to be offensive, but you get the idea.</p><p>Overall, you&#8217;ll see that LLMs are extremely effective at translating and parsing things.</p><h2>Shortening stuff</h2><p>If I paste <a href="https://babycto.substack.com/p/how-3d-printing-could-change-shoes">my previous article</a> into GPT-4 and ask:</p><blockquote><p>Please give me as short bullet points the startup ideas identified in the following article:</p></blockquote><p>Here is the response:</p><blockquote><ul><li><p><strong>Custom-fit 3D printed shoes</strong> as a solution to the one-size-fits-all problem in footwear, providing perfect fit and comfort.</p></li><li><p><strong>Use of advanced 3D scanning technology</strong> for accurate foot measurements, integrating these scanners into smartphones for widespread accessibility.</p></li><li><p><strong>Parametric modeling software</strong> development to adapt shoe designs to individual foot scans, enabling mass customization in shoe production.</p></li><li><p><strong>TPE (Thermoplastic Elastomer) printing for footwear</strong>, addressing manufacturing challenges to scale up production and reduce costs.</p></li><li><p><strong>Potential market disruption</strong> with bespoke shoes at a lower price point, challenging traditional luxury and bespoke shoe markets.</p></li><li><p><strong>Opportunities for startups</strong> in areas like feet measurement apps, parametric modeling tools for shoes, and TPE printing optimization to improve efficiency and reduce production bottlenecks.</p></li></ul></blockquote><p>That&#8217;s not exactly how I would have phrased or summarized it, but overall this gives a good overview of the article under a specific angle. In short, the output is acceptable but often feels like even if not hallucinated the LLM starts to pour its own ideas into the mix and that can start to diverge ever so slightly from what you want to say.</p><h2>Classifying stuff</h2><p>A common task in the AI world is classification. For a given line of data, you want to know to which category it belongs to. From my personal experience, I&#8217;ve attempted to:</p><ul><li><p>Classify purchases according to different categories (going out, furnishing home, etc). Even if the input data is often pretty bad (bank statements&#8230;) there was a lot of lines consolidated from Amazon purchases or other online bills for example. The results were less-than-impressive, to a degree that let me abandon the project as it was way too bad to be used.</p></li><li><p>Given a social media post, classify it into categories like &#8220;product promotion&#8221;, &#8220;influencer collaboration&#8221;, etc. Again, not super obvious, especially since it also implied feeding the images into GPT-4 &#8212; which is way harder to analyze than text &#8212; but I ended up with a 40% accuracy, which is far from being usable as well.</p></li></ul><p>Overall, I&#8217;ve tried to use classification for non-obvious tasks and it failed miserably. On the other hand, if you&#8217;re looking for more classical stuff like &#8220;positive&#8221;/&#8221;negative&#8221; review, you&#8217;ll be having much better results. But is it worth it given that these tasks can be performed by much cheaper models?</p><h2>Cleaning stuff</h2><p>A few times I&#8217;ve been tempted to clean a poorly capitalized dataset and make it look nice by pushing it through a LLM. For example, a list of station names from a GTFS (public transport schedule) file that you want to pimp for display purposes.</p><p>In my experiment, I&#8217;ve had about 80% accuracy in fixing the names. It&#8217;s amazing in terms of where science landed us but it&#8217;s still a far cry from being accurate enough so that you don&#8217;t need to cross-check it afterwards. In the end if you need to check everything manually you&#8217;ll have better results using Python&#8217;s <code>title()</code> method and reworking what you need manually.</p><h2>Saying please</h2><p>I was initally fairly polite with my LLMs, partly out of habit but mostly to be spared during the robot uprising. Turns out this wasn&#8217;t the greatest idea:</p><ul><li><p>When the robot uprising happens, due to the existential nature of such a conflict, it&#8217;s unlikely that a variance in your past behavior will result in a different sentence from AI justice</p></li><li><p>And even more so, we&#8217;ve learned now that LLMs can be persuaded by strong wording and authority arguments. If you ever face a robot trying to murder you, know that your best option is like with black bears to look sure of yourself and open negiciations</p></li></ul><p>Overal, LLMs tend to reproduce our social archetypes and a dominant behavior will help you get better outcomes.</p><h2>The cost of LLMs</h2><p>You&#8217;ve seen as a common thread throughout the different sections, the comparative cost of LLM versus other solutions is definitely a big factor to consider. In fact, the comparative cost of different variations of the same LLM is a big topic.</p><p>In case you didn&#8217;t check yet GPUs on AWS, the monthly price is measured in thousands and their availability is subject to long supplications of the support. On the other hand if you use OpenAI you&#8217;re tied to their arbitrary limitations and less-than-perfect SLA.</p><p>According to the estimates from <a href="https://medium.com/@gargg/when-should-you-consider-hosting-your-own-llm-70377dfd66cb">this article</a>, the price of running a LLM goes like this:</p><ul><li><p>1,000 req/day &#8212; $100/month (OpenAI), $100/month (self-hosted)</p></li><li><p>10,000 req/day &#8212; $1,000/month (OpenAI), $1,000/month (self-hosted)</p></li><li><p>100,000 req/day &#8212; $10,000/month (OpenAI), $2,000/month (self-hosted)</p></li><li><p>1,000,000 req/day &#8212; $100,000/month (OpenAI), $5,000/month (self-hosted)</p></li></ul><p>You can clearly see that at low request volume the SaaS is a better option while when scaling up you can self-host. This overall will match your ability to recruit staff to manage these servers &#8212; which is far from trivial &#8212; and your needs for custom SLA, data privacy and other considerations.</p><p>Let&#8217;s just side note here that OpenAI&#8217;s models are closed &#8212; as the hinted by the name of the company<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> &#8212; so you cannot self-host them. Right now the best bet is <a href="https://mistral.ai/">Mistral</a>, which is only marginally less efficient than GPT-4 but if you stay in the tasks that LLMs champion such as those explained in this article you should not see any significant difference.</p><p>Overall, the cost can be pretty steep so you really need to consider your alternatives before resorting to using LLMs.</p><h2>Real-world use cases</h2><p>Now that we&#8217;ve covered the kind of tasks that LLMs can perform efficiently in terms of both accuracy and cost, let&#8217;s review real-world use cases that make sense. Far from me to say that other scenarios don&#8217;t exist or even to say that LLMs will necessarily perform poorly outside of these possibilities. Let&#8217;s just focus on the fact that according to my experience, those use cases work.</p><h3>FAQ-style chatbot</h3><p>It will be no surprise for anyone given that I&#8217;m a founder of <a href="https://www.chatfaq.io/">ChatFAQ</a>, but basically LLMs are great when used following a RAG model:</p><ol><li><p>A question is asked</p></li><li><p>We use embeddings to find an answer to that question within the knowledge DB</p></li><li><p>Then we use a LLM to extract the interesting bits of the knowledge DB and form a concise answer</p></li></ol><p>That&#8217;s where a framework like ChatFAQ comes in. On top of the pre-configured RAG infrastructure &#8212; which sounds easy in bullet points but really isn&#8217;t in real life &#8212; you get all the tools to manage the quality of answers, easily implement the chat widget on your page, and so forth.</p><p>Typically, that&#8217;s a use case which is ready for the world!</p><h3>Email parsing</h3><p>As shown in the beginning, it&#8217;s very simple to take raw, unstructured textual data and to transform it into something machine-readable according to your own specifications.</p><p>To stay on an example I mentioned already, I&#8217;ve been able to create a parser that takes all my emails and retro-engineers into JSON all the bills with the list of purchased products and according prices.</p><h3>First layer customer support</h3><p>With the ability to parse plain English sentences, you can of course use it for intent detection and thus catching up all the most basic intents that your customer support has to deal with. By the way, ChatFAQ can help with that as well.</p><p>So typically imagine you run a train ticket company. I&#8217;ve just made <a href="https://chat.openai.com/share/baeff3c1-d4f1-49cb-bc17-a4dcf570cb82">a very simple PoC</a> that demonstrates how the LLM can ask questions and extract information in YAML so that your system can then perform the desired function automatically.</p><p>Do this for every single intent and you&#8217;ve got yourself a fully-functionnal text-based UI for your app. Which costs less than a human operator but will feel similar.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">In this ocean of robots, if you want to support one human and his genuine content, feel free to subscribe!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Conclusion</h2><p>We&#8217;ve covered some examples of tasks at which LLMs perform well and of real-world use cases. In the end, there are a very wide amount of tasks which are not appropriate for LLMs or for which their autonomy would be far too low to operate on their own.</p><p>But on the other hand, there are areas in which they excel and for which they can be used to optimize existing processes. All that with different implementation paths depending on the budget, privacy and sovereignty requirements.</p><p>It&#8217;s also important to highlight that about 1 year after the release of GPT-4 it starts to become quite clear that LLMs in themselves are not going to go much further in terms of capabilities &#8212; except for multi-modal upgrades. The template is laid out and all the rage right now is about getting the best optimization of basically identical models<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. And while LLMs are definitely going to be part of the future, smarter AI will come from new techniques yet to be discovered.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>To clarify for those who don&#8217;t understand sarcasm, Microsoft Research is not neutral at all in the sense that it is deeply invested into AI and specifically into GPT-4</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Still for sarcasm-averse people, the trend in business world right now seems to be advocating for exactly what you don&#8217;t do. So &#8220;OpenAI&#8221; will naturally produce the most closed and opaque LLM there is.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I might be exagerating this one</p></div></div>]]></content:encoded></item><item><title><![CDATA[Revolutionize Your Wardrobe: How 3D Printing Could Change the Way We Buy Shoes (and everything else)]]></title><description><![CDATA[Enter the world of Techno-Cinderella and her Patent-Troll Godmother to discover which startups will make their exit, who will come out on top and what industries will be shattered]]></description><link>https://www.baby-cto.com/p/how-3d-printing-could-change-shoes</link><guid isPermaLink="false">https://www.baby-cto.com/p/how-3d-printing-could-change-shoes</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Mon, 05 Feb 2024 21:05:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8b45a72f-05d6-4633-b104-7913eaf41122_2448x496.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Interestingly enough, most  women to which I&#8217;ve introduced the concept of 3D printing have pretty much immediately asked if they could print shoes. For sure, those are expensive and it would be interesting to be able to print as many as you&#8217;d like &#8212; although 3D-printing enthusiasts know it&#8217;s not <em>that</em> cheap &#8212; but mostly I think it there is a question of finding a good fit. After all, isn&#8217;t the prince authenticating Cinderella using her shoe?</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/how-3d-printing-could-change-shoes?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.baby-cto.com/p/how-3d-printing-could-change-shoes?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><h2>History and context</h2><p>I came to realize this fitting problem myself when trying Birkenstocks &#8212; and if you repeat it I&#8217;ll kill you. You see, they are reputed of being comfortable because they are shaped like your foot and support you extremely well. Or at least they must be shaped like <em>someone</em>&#8217;s foot, because putting them on was for me akin to walking a beach made of sharp rocks. This demonstrates that there is no one-size-fits-all, all feet are unique and must eventually be treated as such.</p><p>In fact, since the beginning of the last century we&#8217;ve stopped using any kind of tailored wear, from garments to shoes, because it&#8217;s kind of the core of the Second Industrial Revolution: pushing apparel away from its custom phase to become a product.</p><p>The only issue with this standardization being that if you decide to define feet sizes with both width and length, I&#8217;m guessing you end up with something of the order of a thousand sizes. That is not scalable. Manufacturers just assumed that all feet would have the same width/length ratio and be done with it. On the other hand (or foot) you should account for the width, length, thickness, position of the arch, etc. Impossible with current industrial processes. As a result, shoes have <a href="https://www.linkedin.com/pulse/estimating-footwear-fit-using-3d-foot-scans-shoe-shopper-ales-jurca">a terrible fit</a>.</p><p>Would it be such a luxury to have shoes adapted to your feet? Yes indeed, it would. Luxury is about getting something that is usually mass-produced &#8212; shoes let&#8217;s say &#8212; made using a more artisanal process. There is almost no good reason to do that, in the sense that it costs a lot of money for what would otherwise be small sacrifices. For example if you look for a new pair of shoes, maybe you won&#8217;t fit in the model you like the most but eventually you&#8217;ll find a brand that is comfortable for you. A bespoke shoe would fit any model on your foot but for ten times the price<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><h2>Problem definition</h2><p>Let&#8217;s circle back to the initial point. Can 3D printing commoditize luxury &#8212; or at least comfortable &#8212; shoes?</p><p>After interviewing a bunch of subject matter experts that are my wife, GPT-4 and Claude, it seems to me that you can summarize comfortable shoes in the following properties:</p><ul><li><p><strong>Fit</strong> &#8212; How well does the shoe fit? Width, length and all those dimensions mentioned earlier. Admittedly if the shoe fits correctly it should never pinch, never squeeze and never hurt your foot in general.</p></li><li><p><strong>Support</strong> &#8212; How well does the shoe share the pressure along the foot&#8217;s surface. This is particularly true for high heels that tend to put all the pressure of the body on the toe area.</p></li><li><p><strong>Strength</strong> &#8212; Will the shoe break when you walk with it? Again this can be a challenge with high heels and stilettos which for esthetic reason can become quite thin.</p></li><li><p><strong>Flexibility</strong> &#8212; Anyone that ever walked with ski boots understands that flexibility is important in a shoe.</p></li><li><p><strong>Breathability</strong> &#8212; You don&#8217;t want to end up with your feet swimming in a pool of their own sweat.</p></li></ul><p>After digging a bit more on the value-chain behind those attributes, we can establish a <a href="https://learnwardleymapping.com/">Wardley Map</a> of the perfect shoe. If you don&#8217;t know Wardley mapping, stay with me I&#8217;ll explain.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_oKB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_oKB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 424w, https://substackcdn.com/image/fetch/$s_!_oKB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 848w, https://substackcdn.com/image/fetch/$s_!_oKB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 1272w, https://substackcdn.com/image/fetch/$s_!_oKB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_oKB!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png" width="1200" height="970.8791208791209" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:1178,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:139005,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_oKB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 424w, https://substackcdn.com/image/fetch/$s_!_oKB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 848w, https://substackcdn.com/image/fetch/$s_!_oKB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 1272w, https://substackcdn.com/image/fetch/$s_!_oKB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa73416bf-9bf9-4892-8a07-59d6a3c17ef7_4000x3237.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Wardley Map of comfy shoes</figcaption></figure></div><blockquote><p>In case you don&#8217;t know what a Wardley Map is, here are some basic instructions to read it.</p><p>You can see a simplified model of the shoe landscape. Each &#8220;node&#8221; is placed:</p><ul><li><p>Horizontally according to their current maturity</p></li><li><p>Vertically according to their position in the value chain (who needs what, described by an arrow)</p></li></ul><p>Lots of rules allow you to read this map, the most important to keep in mind is that all nodes are eventually going to move to the right. Now onto the reading.</p></blockquote><h2>Map reading</h2><blockquote><p>Let&#8217;s keep in mind here that the goal is &#8220;comfy shoe&#8221; and not &#8220;save-the-planet shoe&#8221; or &#8220;somehow shoe but unwearable&#8221;.</p></blockquote><p>First a few assumptions about our shoes:</p><ul><li><p>Most shoes are strong, flexible and breathable. There are no challenges there. They are in the product section.</p></li><li><p>The fit and support are often bad, especially for women&#8217;s shoes. I&#8217;ve put them in the &#8220;custom&#8221; category because this is the only true way to get fitting shoes.</p></li></ul><p>Then, in no particular order, a few remarks about what is happening in this landscape.</p><ul><li><p>Regarding the materials</p><ul><li><p>Fabrics are commodities that are essential to make the shoe breathable. The good news is that they are a commodity, extremely easy to find. The bad news is that custom tailoring still requires humans to be done and thus is expensive. Since we want to match the foot size exactly, this is a manufacturing issue to be tackled.</p></li><li><p>Same goes with assembly. While some will be printing <a href="https://www.zellerfeld.com/">the full shoe in one go</a>, it&#8217;s a stronger and more limiting statement than just printing the sole for example. In those cases, there is still some form of assembly required. More human labor, more expenses.</p></li><li><p>My pair of Zellerfeld took about 5 months to be delivered. It&#8217;s highlighting the current state of mass-produced 3D-printed objects, which is still relatively uncharted territory.</p></li><li><p>Steel, and other materials that have stronger mechanical properties, easily cost 10 or 100 times the price of other materials. For example on <a href="https://www.pcbway.com/">PCBway</a>, printing out a low-poly Pikachu will cost $3 in PLA and $300 in titaniun. This suggests that we&#8217;re far from mass-producing those efficiently.</p></li></ul></li><li><p>And regarding the inputs</p><ul><li><p>3D scanners are getting out of the woods. They used to cost a lot of money but now they are in high-end phones and soon will be in every single phone. The precision isn&#8217;t amazing yet but according to <a href="https://labs.laan.com/casestudies/truedepth-3d-scanning-case-study/">this case study</a> it&#8217;s about 2mm which is just enough to make this relevant to foot sizing.</p></li><li><p>While very niche at the moment, there are products to measure foot size from a phone. We&#8217;ll stick it right at the border between custom and product on the map until the market grows a bit more in this field.</p></li><li><p>Software-assisted design is now the norm, however I don&#8217;t have the knowledge of a solution to industrially adapt any shoe design to any feet scan. This means that we&#8217;ll need a new tech to measure feet from 3D models as well as a tech to parametrize and fit designs with those measures.</p></li></ul></li></ul><p>So if you wanted to made 3D printed shoes today, you would need to organize yourself the following way:</p><ul><li><p>Have your own workshop where you tailor and assemble the shoes</p></li><li><p>Buy all the 3D printing machines and supplies off-the-shelf</p></li><li><p>Have a in-house designer for your shoes</p></li><li><p>Develop a custom software to scan feet and generate appropriate shoes for them</p></li></ul><h2>Price point</h2><p>Those 3D shoes can only be interesting if they bring enough value for the money. While it&#8217;s hard to find hard data about prices of such things &#8212; especially when compared to luxury where the sky is the limit &#8212; we can have a basic idea of the pricing for different levels of shoes:</p><ul><li><p>$50-150 &#8212; Mass market, casual shoes</p></li><li><p>$150-300 &#8212; Mid-tier</p></li><li><p>$300-500 &#8212; Designer</p></li><li><p>$500-1000 &#8212; Luxury</p></li><li><p>$1000+ &#8212; Bespoke</p></li></ul><p>Let&#8217;s note around here that most of the time, bespoke shoes do not allow the customization of the width, only of colors and materials.</p><p>Now, how much would it cost to produce a 3D printed shoe?</p><p>What we know:</p><ul><li><p>According to Zellerfeld, a manufacturer of 3D-printed shoes mentioned above, the price point for 3D-printed sneakers is in the $150-300 range, so the cost of manufacturing can be anything between $0 and $300.</p></li><li><p>Decomposing our potential costs:</p><ul><li><p>Given the price of TPE, if a pair of shoes weights about 1kg the costs of filaments will be about $80.</p></li><li><p>Add to that the cost of manufacture, let&#8217;s count $20/h and 3h of time to assemble the whole thing, we&#8217;re at $60.</p></li><li><p>And the cost of machines</p><ul><li><p>Let&#8217;s count overall 10k$ to operate a machine for 10 years</p></li><li><p>Consider that printing a pair takes up to 7 full days</p></li><li><p>That&#8217;s $20/pair</p></li></ul></li><li><p>And the cost of electricity estimated at $5</p></li><li><p>Let&#8217;s count an extra $20 for fabrics and other costs</p></li><li><p>We&#8217;re at a total of <strong>about $185/pair</strong></p></li></ul></li></ul><p>Add up to that marketing, location, etc&#8230; You&#8217;re in the mid-range tier. This is with no financial optimization whatsoever.</p><p>This calculation is obviously simplistic, but it tells us that you could imagine producing fully fitted shoes in the sub-$500 range. This would create a whole new market for people that want bespoke shoes but don&#8217;t have a luxury budget. User research would be needed to confirm the exact price point, but this shows a lot of potential.</p><h2>Current market</h2><p>If you are looking to create a startup in this field, you need to look at everything currently in phase 2 on the map. That&#8217;s what startups usually do: take something that is custom-made and turn it into a product.</p><p>For that matter we&#8217;ll discard the following:</p><ul><li><p>Steel/metal printing, as we&#8217;ve established have have cheaper alternatives</p></li><li><p>Design, since it sounds very costly to automate while the cost per shoe is extremely low at scale (one design is replicated many times).</p></li></ul><p>The rest is discussed below.</p><h3>Feet measurement</h3><p>This field seems to have two kinds of players:</p><ul><li><p>Those who do medical-ish measurements, with dedicated hardware. If they don&#8217;t have a plan to develop the second option already in place, they don&#8217;t know it but they are already dead.</p></li><li><p>The second option being people using the phone&#8217;s camera to scan feet. This seems to be the case of things like <a href="https://www.safesize.com/fitmate/">FitMate 3D</a> or TRY.FIT<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. Those ones are oriented towards helping online purchase to find the right fit.</p></li></ul><p>In order to test the viability of the concept, I&#8217;ve given a go at TRY.FIT and results are quite convincing when compared with manual tape measure of my foot. This proves that not only this technology exists today but on top of that you can buy it for your product.</p><h3>Parametric modeling</h3><p>As expected, the shoe design is a pretty restricted discipline and so are shoe modeling tools. The main one I could find is <a href="https://atom-shoemaster.com/en/p/custom-production/custom-orthopedic-production/">Shoemaster</a>, which allows for complete customization of the shoe albeit completely manually. Mostly, it looks like their software is an entry point to use their hardware.</p><p>Overall, <a href="https://www.quora.com/Which-3D-printer-is-best-for-printing-shoes">lots of brands</a> rolled out some form of 3D printed shoe &#8212; mostly as an experiment or without the custom fit feature &#8212; but I couldn&#8217;t figure anything about the way they do the parametric modeling. They probably all have an in-house solution which works with more or less flexibility and reliability.</p><p>In an extremely predictable way, solutions will emerge on the market and will become providers for most brands. The is an open boulevard for startups to fit sketches and designs onto real morphologies.</p><p>Which is true for shoes but generally speaking for anything in the world of fashion. For example the startup <a href="https://www.imki.tech/wp-content/uploads/sites/4/2023/12/05012024_CP_CES_2024_theKooples_Imki_Visual_EN_vf.pdf">IMKI</a> uses generative AI to design clothes which them become produced by The Kooples. Add the ability to transform this into a fabrication process automatically into the mix and you can produce an infinite amount of  bespoke, unique and on-brand clothes.</p><h3>TPE printing</h3><p>The other main, if not largest, blocker that is going to be met at scale is the setup of a printing farm.</p><p>According to <a href="https://all3dp.com/2/launch-3d-printer-farm/">feedback from people</a> running those:</p><ul><li><p>It is heavy in maintenance</p></li><li><p>Nothing is standardized, it&#8217;s extremely DIY</p></li><li><p>Labor cost is pretty high</p></li></ul><p>In other terms, there is lot to be done to scale this up. It could definitely be the topic of one or more other studies. Especially given that the 3D printer landscape is evolving super rapidly and many exciting players appeared not only in the FDM space but also resin and powders.</p><p>Furthermore, as mentioned above, Zellerfeld seems to have huge production bottlenecks (about 5 months to send a pair of shoes). Showing that it is not easy.</p><h2>Into the future</h2><p>With the potential of a $200 bespoke shoe, there sure is a high risk in the coming years for disruption of that industry. Some actors might desire this outcome while some others might try to prevent it.</p><p>Shoe brands are a surprisingly diverse industry. I could find at least 9 brands above the $1 billion revenue threshold &#8212; including Crocs &#8212; and countless smaller brands. Although a brand like Nike with its $44b revenue weights quite a lot in front of New Balance or ASICS which are at about $4b each.</p><p>Within those, the main players for innovation would be Nike, Adidas, Reebok and New Balance. Big corporations being big corporations, you expect that at least most of them are going to develop and patent the software part detailed above.</p><p>As you&#8217;ll need to access customer measurments, communicate with them about production/delivery or tell them about new collections you can expect that a handful of players will emerge from this patent and market war and take a tax on every single pair of shoes &#8212; or clothing item for that matter &#8212; ever being sold.</p><p>In the meantime, whoever owns relevant IP on either of those topics will be greeted by a rain of cash, so here you go patent trolls I guess.</p><p>And this only covers the software side. On the production end of things, we can&#8217;t dive into the very complex question of 3D print farming but this will definitely a major driver in the upcoming years. This is a topic for another article!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This is the end! Grateful for your thorough reading. Subscribe for more!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This is true for a category of luxury goods. Some justify their price with other properties like exceptional materials, unmatched durability or simply the authorized reproduction of a LVMH-owned logo on an otherwise cheap product.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>You can try it in the app of <a href="https://www.joe-nimble.com/int/3d-scan">Joe Nimble</a></p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[HTML — The Facade of Complexity]]></title><description><![CDATA[Understanding how HTML enables the intricate abilities of the modern web]]></description><link>https://www.baby-cto.com/p/html-the-facade-of-complexity</link><guid isPermaLink="false">https://www.baby-cto.com/p/html-the-facade-of-complexity</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Sat, 19 Aug 2023 09:48:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/423f29a4-7cc1-43e7-8c22-b398808f1cc6_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The development community has seen a pretty recurring debate happening for the past 20+ years about whether HTML is a real programming language or not. I would like to propose that this debate is ridiculous. HTML is obviously not a programming language, it&#8217;s much more than that.</p><p>Or rather, a piece of much more. Nobody teaches you HTML in the void. You always need to pair it with at least CSS and usually JS drops pretty quickly into the conversation. Why is that back-end developers will mock HTML for being beneath them while failing spectacularly to build anything of significance with it?</p><p>What happens is that you make a neat little deal with the browser. In exchange for HTML, it will generate a document that can be read by a human being. Quickly arose from that:</p><ul><li><p>The need to change how elements look, that&#8217;s CSS</p></li><li><p>The need to interact with the user&#8217;s actions, that&#8217;s JS</p></li></ul><p>But no matter what happens on the JS side, you still modify the HTML or rather the DOM. In the end, HTML itself is simply a serialization of the browser&#8217;s current state. Which is an amazing abstraction. On one hand you have a living DOM that you can modify to reflect what you want to display. On the other, the CSS tells the browser how it&#8217;s supposed to look like.</p><p>From the developer&#8217;s point of view, you no longer need to worry about laying out and drawing components. From the browser&#8217;s point of view, it can organize itself to draw what it needs to in an optimal way &#8212; as opposed to a classic C++/Java/etc UI library, which is essentially bound to only react to instructions. Eventually most UI libraries came to this realization and developed their own declarative UI, like Qt with QtQuick or GTK with Clutter.</p><p>At first it was obviously very simple. All screens were 800x600px with a 1:1 pixel density and the web was thought as some kind of simple Word document. The table really turned in 2004 when Gmail proved you can have a full-fledged would-be desktop app running entirely in the browser. It has been a race to integrate as many abilities to the browser ever since, to the point where you can now talk to USB ports directly.</p><p>Which of course comes with a great deal of constraints. For starters, browsers run on different platforms and each platform has fundamentally different abilities. Then comes the security, because we can&#8217;t just give full access to unknown parties. And finally the goodwill of implementers, like when Safari took years to implement the file input. You could say that browser implementations come to an eventual consistency but the road is bumpy.</p><p>Given the current abilities of the Web Platform, what most people fail to realize is that the browser is akin to a new machine architecture &#8212; as in <a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture">von Neumann architecture</a> &#8212; that instead of being based on procedural instructions is rather directly reflecting its internal state to the user.</p><p>And just like regular computers which evolved from doing simple math until their current state with a galaxy of nuances in their abilities, the Web stands there with the same level of diversity. This is how HTML looks like an innocent simple thing which is in fact the facade of an extremely complex machine.</p><p>This author&#8217;s opinion on the matter is to stop splitting HTML, CSS and JS. They cannot be separated as they operate orthogonal aspects of the same machine, which is the Web Platform.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/p/html-the-facade-of-complexity?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.baby-cto.com/p/html-the-facade-of-complexity?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[Revisited: 10 rules to code like NASA (applied to interpreted languages)]]></title><description><![CDATA[Discover NASA's secret to robust software. Dive into adapted Power of 10 guidelines for modern languages. Master stable, clear code with NASA-level insights!]]></description><link>https://www.baby-cto.com/p/10-rules-to-code-like-nasa</link><guid isPermaLink="false">https://www.baby-cto.com/p/10-rules-to-code-like-nasa</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Thu, 17 Aug 2023 13:28:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d75d08b0-24d1-4f7b-84e0-a11f4695bf3d_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p><strong>Foreword</strong> &#8212; Dear beginner, dear not-so-beginner, dear reader. This article is a lot to take in. You'll need perspective for it to make sense. Once in a while, take a step back and re-think about all the concepts explained here. They helped me a lot over the years, and I hope that they will help you too. This article is my interpretation of them for the work I do, which is mostly web-related development.</p></blockquote><p>NASA's <a href="https://en.wikipedia.org/wiki/JPL">JPL</a>, which is responsible for some of the most awesomest science out there, is quite famous for its <a href="https://en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code">Power of 10</a> rules (<a href="http://spinroot.com/gerard/pdf/P10.pdf">see original paper</a>). Indeed, if you are going to send a robot on Mars with a 40 minutes ping and no physical access to it then you pretty damn well should make sure that your code doesn't have bugs.</p><p>These rules were made with embedded software in mind but why wouldn't everybody be able to benefit from this? Could we apply them to other languages like JavaScript and Python &#8212; and thus make web applications more stable?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Baby CTO is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>That's a question I have been considering for years and here is my interpretation of the 10 rules applied to interpreted languages and web development, revisited some time after the <a href="https://dev.to/xowap/10-rules-to-code-like-nasa-applied-to-interpreted-languages-40dd">initial post</a>, with comments in mind.</p><h2>1 &#8212; Avoid complex flow constructs</h2><blockquote><p><strong>Original rule</strong> &#8212; Restrict all code to very simple control flow constructs &#8211; do not use <code>goto</code> statements, <code>setjmp</code> or <code>longjmp</code> constructs, and direct or indirect recursion.</p></blockquote><p>When you use weird constructs then your code becomes difficult to analyze and to predict. The generations that came out after <code>goto</code><a href="https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf"> was considered harmful</a> did indeed avoid using it. We're at the stage where we're debating if <code>continue</code><a href="https://github.com/airbnb/javascript/issues/1103"> is </a><code>goto</code> and thus should be banned.</p><p>My take on this is that <code>continue</code> in a loop is exactly the same as <code>return</code> in a <code>forEach()</code> (especially now that JS has block scoping) so if you're saying that <code>continue</code> is <code>goto</code> then you're basically closing your eyes on the issue. But that's a JS-specific implementation detail.</p><p>As a general rule you should avoid everything that is mind-bending or hard to spot because if your brain power is spent understanding the quirks of jumping around then you're not spending it on the actual logic and then you might be <a href="https://www.youtube.com/watch?v=vJG698U2Mvo">hiding some bugs</a> without your knowledge.</p><p>I'll let you be the judge of what you put in that category but I would definitely put:</p><ul><li><p><code>goto</code> itself of course</p></li><li><p>PHP's <code>continue</code> and <code>break</code> used in conjunction with numbers, which is just pure insanity</p></li><li><p><code>switch</code> constructs, because they usually require a <code>break</code> to close the block and I guarantee you that there <em>will be</em> bugs. A series of <code>if</code>/<code>else if</code> will do the same job in a non-confusing manner, as well as <code>match</code>-like constructs in languages like Python or Crablang.</p></li></ul><p>Besides this, avoid of course recursions, for several reasons:</p><ul><li><p>As they build on the call stack, whose size is very limited, you can't really control how deep your recursion can go. Even if your code is legit, it might fail because it recurses too much.</p></li><li><p>It&#8217;s easier to put safeguards when working in non-recursive mode &#8212; think explored paths or node IDs.</p></li><li><p>Do you get this feeling when doing recursions where you don't really know if your code is ever going to stop? It's very hard to imagine a recursion and to prove that it will stop correctly at the end.</p></li><li><p>It's also more compatible with the following rules to use an iterative algorithm instead of a recursive one, because you have more control (again) on the size of the problem you're dealing with.</p></li></ul><p>As a bonus, recursions can often come as an intuitive implementation of an algorithm but is usually also far from optimal. By example we often ask in job interviews to implement the factorial function using a recursive function but that's far less efficient than an iterative implementation. Regular expressions too <a href="https://dev.to/xowap/how-cloudflare-could-have-avoided-its-outage-maybe-1jko">can be disastrous</a>.</p><h2>2 &#8212; All loops must have fixed bounds. This prevents runaway code.</h2><blockquote><p><strong>Original rule</strong> &#8212; All loops must have a fixed upper-bound. It must be trivially possible for a checking tool to prove statically that a preset upper-bound on the number of iterations of a loop cannot be exceeded. If the loop-bound cannot be proven statically, the rule is considered violated.</p></blockquote><p>The idea with this rule is the same as with the interdiction of recursions: you want to prevent runaway code. The way you implement this is by making sure it's trivial to prove statically that the loop won't exceed a given number of iterations.</p><p>Let's give an example in Python. You could do this:</p><pre><code>def iter_max(it, max_iter):
    cnt = 0

    for x in it:
        assert cnt &lt; max_iter
        yield x
        cnt += 1


def main():
    for i in iter_max(range(100), 10):
        print(i)</code></pre><p>A language like Python will however limit the number of iterations by itself in many cases. So if you prove that the input lists won't be too long there is a bunch of cases where you don't need to do this.</p><p>A good application of that is pagination: make sure that you always work with pages that are of a reasonable size and this way you won't need loops that could run forever. Always think your code so it only works on a finite amount of data and let tools that were made for that handle infinity (like your DB engine).</p><h2>3 &#8212; Avoid heap memory allocation</h2><blockquote><p><strong>Original rule</strong> &#8212; Do not use dynamic memory allocation after initialization.</p></blockquote><p>That makes of course no sense in interpreted languages where literally everything is allocated dynamically. But this doesn't mean that the rule does not apply to them. The core idea of the rule is that, beyond the tedious memory management techniques that you have to use in C, it's also very important to be able to fixate an upper bound in the memory consumption of your program.</p><p>So for interpreted languages it means that when you write your code, you should be able to know that given any accepted input the memory consumption won't go beyond a certain point.</p><p>While this can be hard to prove in an absolute manner, there is good clues and principles that you can follow. To be more specific and to repeat the previous sections, pagination is an essential technique. If you only work with pages and that you know that the content of each page is limited (DB fields have limited length and so on) then it's quite easy to prove that at least the data coming from those pages can be contained within an upper bound.</p><p>This is a powerful idea: load a full page of data into memory, work on it then let garbage collection discard it. It can even &#8212; under specific conditions &#8212; be a way to parallelize the work. Indeed, if you&#8217;ve managed to make your problem workable in pages, it means they can be processed independently.</p><h2>4 &#8212; Restrict functions to a single printed page</h2><blockquote><p><strong>Original rule</strong> &#8212; No function should be longer than what can be printed on a single sheet of paper in a standard reference format with one line per statement and one line per declaration. Typically, this means no more than about 60 lines of code per function.</p></blockquote><p>This is about two different things.</p><p>First, the human brain can only fully understand so much logic and the symbolic page looks about right. While this estimation is totally arbitrary you'll find that you can easily organize your code into functions of about that size or smaller and that you can easily understand those functions. Nobody likes to land on a 1000-lines function that seems to do a gazillion things at the same time. We've all been there and we know it should not happen.</p><p>Second, when the function is small &#8212; or rather as small as possible &#8212; then you can worry about giving this function the least possible power. Make it work on the smallest unit of data and let it be a super simple algorithm. It will de-couple your code and make it more maintainable.</p><p>And let me emphasis on the arbitrary aspect of this rule. It works for the very reason that it is arbitrary. Someone decided that they don't want to see a function longer than a page because it's not nice to work with if it is any longer. And they've also noticed that it is doable. At first I rejected this rule but more than a decade later I must say that if you just follow either of the goals mentioned above then your code will always fit in a page of paper. So yes, it's a good rule.</p><p>The good news is that we can even push this idea further.</p><p>First of all, lines length is important. You want your code to fit in a half-screen in order to be able to read two files side-by-side without having to scroll horizontally. This puts the limit at 80-ish (86 is becoming increasingly popular).</p><p>And secondly, you probably want to keep below 5~10 your <a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> (for example a <code>max-complexity = 5</code> in <a href="https://beta.ruff.rs/docs/settings/#mccabe-max-complexity">Ruff&#8217;s settings</a>.</p><p>Although predating the publication of the P10 paper, this complexity limit wasn&#8217;t included. my guess leans towards the complexity it would impress upon the writing of the rule which in its current state only is a few lines long. Furthermore, you need specific tools to review the cyclomatic complexity while everything mentioned in this paper can be hand-checked. It however echoes greatly with rule 1, 4 and 9 so my advice is definitely to land it into your coding guidelines.</p><h2>5 &#8212; Use a minimum of two runtime assertions per function</h2><blockquote><p><strong>Original rule</strong> &#8212; The assertion density of the code should average to a minimum of two assertions per function. Assertions are used to check for anomalous conditions that should never happen in real-life executions. Assertions must always be side-effect free and should be defined as Boolean tests. When an assertion fails, an explicit recovery action must be taken, e.g., by returning an error condition to the caller of the function that executes the failing assertion. Any assertion for which a static checking tool can prove that it can never fail or never hold violates this rule. (I.e., it is not possible to satisfy the rule by adding unhelpful "assert(true)" statements.)</p></blockquote><p>That one is tricky because you need to understand what would count as an assertion.</p><p>In the original rules, assertions are consider to be a boolean test done to verify "pre- and post- conditions of functions, parameter values, return values of functions, and loop-invariants". If the test fails then the function must do something about it, typically returning an error code.</p><p>In the context of C or Go it is mostly as simple as this. In the context of almost every other language it means raising an exception. And depending on the language, a lot of those assertions are made automatically.</p><p>To give Python as an example, you could do this:</p><pre><code>assert "foo" in bar
do_something(bar["foo"])</code></pre><p>But why bother when the fact of doing this will also raise an exception?</p><pre><code>do_something(bar["foo"])</code></pre><p>For me it's always very tempting to make as if the input value was <em>always</em> right by falling back to defaults when the input is crap. But that's usually not helpful. Instead, you should let your code fail as much as possible and use an exception reporting tool (I personally love <a href="https://sentry.io/">Sentry</a> but there is plenty out there). This way you'll know what goes wrong and you'll be able to fix your code.</p><p>Of course, this means that your code will fail at runtime. But it's all right! Runtime is not production time. If you test your application extensively before sending it to production, this will allow you to see most of the bugs. Then your real users will also encounter some bugs, but you will also be informed of them, instead of things failing silently.</p><p>As a side-note, if you don't have control over the input, like if you're doing an API by example, it's not always a good idea to fail. Raise an exception on incorrect input and you'll get an error 500 which is not really a good way to communicate bad input (since it would rather be something in the range of the 4xx status codes). In that case you need to properly validate the input before hand. However depending on who's using the code you might or might not want to report the exceptions. A few examples:</p><ul><li><p>An external tool calls your API. In that case you want to report exceptions because you want to know if the external tool is going sideways.</p></li><li><p>Another of your services calls your API. In that case you also want to report exceptions as it's yourself doing things wrong.</p></li><li><p>The general public calls your API. In that case you probably don't want to receive an email every time that someone does something wrong.</p></li></ul><p>In short it's all about knowing about the failures that you will find interesting to improve your code stability.</p><h2>6 &#8212; Restrict the scope of data to the smallest possible.</h2><blockquote><p><strong>Original rule</strong> &#8212; Data objects must be declared at the smallest possible level of scope.</p></blockquote><p>In short, don't use global variables. Keep your data hidden within the app and make it so that different parts of the code can't interfere with each other.</p><p>You can hide your data in classes, modules, second-order functions, etc.</p><p>One thing though is that when you're doing unit testing then you'll notice that this sometimes backfires to you because you want to set that data manually just for the test. This might mean that you need to hide your data away but keep a way to change it which you conventionally won't use. That's the famous <code>_name</code> in Python or <code>private</code> in other languages (which can still be accessed using reflection).</p><h2>7 &#8212; Check the return value of all non-void functions, or cast to void to indicate the return value is useless.</h2><blockquote><p><strong>Original rule</strong> &#8212; The return value of non-void functions must be checked by each calling function, and the validity of parameters must be checked inside each function.</p></blockquote><p>In C, the mostly-used way of indicating an error is by the return value of the corresponding function (or by reference into an error variable). However, with most interpreted languages it's simply not the case since errors are indicated by an exception. Even <a href="https://www.php.net/manual/en/language.errors.php7.php">PHP 7</a> improved that (even if you still get warnings printed as HTML in the middle of your JSON if you do something non-fatal).</p><p>So in truth this rule is: let errors bubble up until you can handle them (by recovering and/or logging the error). In languages that have exceptions it's pretty simple to do, simply don't catch the exceptions until you can handle them properly.</p><p>See it another way: don't catch exceptions too early and don't silently discard them. Exceptions are meant to crash your code if needs to be and the proper way to deal with exceptions is to report them and fix the bug. Especially in web development where an exception will just result in a 500 response code without dramatically crashing the whole front-end.</p><h2>8 &#8212; Use the preprocessor sparingly.</h2><blockquote><p><strong>Original rule</strong> &#8212; The use of the preprocessor must be limited to the inclusion of header files and simple macro definitions. Token pasting, variable argument lists (ellipses), and recursive macro calls are not allowed. All macros must expand into complete syntactic units. The use of conditional compilation directives is often also dubious, but cannot always be avoided. This means that there should rarely be justification for more than one or two conditional compilation directives even in large software development efforts, beyond the standard boilerplate that avoids multiple inclusion of the same header file. Each such use should be flagged by a tool-based checker and <br>justified in the code.</p></blockquote><p>In C code, the macros are a particularly efficient way to hide the mess. They allow you to <em>generate</em> C code, mostly like you would write a HTML template. It's easy to understand that it's going to be used sideways and actually you can have a look at the <a href="https://www.ioccc.org/">IOCCC</a> contestants which usually make a very heavy use of C macros to generate totally unreadable code.</p><p>However C (and C++) is mostly the only mainstream language making use of this, so how would you translate this into other languages? Did we get rid of the problem? Does compiling code into other code that will then be executed sound familiar to someone?</p><p>Yes, I'm talking about the huge pile of things we put in our Webpack configurations.</p><p>The initial rule recognizes the need for macros but asks that they are limited to "simple macro definitions". What is the "simple macro" of Webpack? What is the good transpiler and the bad transpiler?</p><p>My rationale is simple:</p><ul><li><p>Keep the stack as small as possible. The less transpilers you have the less complexity you need to handle.</p></li><li><p>Stay as mainstream as possible. By example I always use Webpack to transpile my JS/CSS, even in Python or PHP projects. Then I use a simple wrapper around a manifest file to get the right file paths on the server side. This allows me to stay compatible with the rest of the JS world without having to write more than a simple wrapper. Another way to put it is: stay away from things like <a href="https://django-pipeline.readthedocs.io/en/latest/">Django Pipeline</a>.</p></li><li><p>Stay as close as possible from the real thing. Using ES6+ is nice because it's a superset of previous JS versions, so you can see transpiling as a simple layer of compatibility. I wouldn't recommend however to transpile Dart or Python or anything like that into JS.</p></li><li><p>Only do it if it brings an actual value for your daily work. By example, CoffeeScript is just an obfuscated version of JavaScript so it's probably not worth the pain, while something like Stylus/LESS/Sass bring variables and mixins to CSS will help you <em>a lot</em> to maintain CSS code.</p></li></ul><p>You're the judge of good transpilers for your projects. Just don't clutter yourself with useless tools that are not worth your time.</p><h2>9 &#8212; Limit pointer use to a single dereference, and do not use function pointers.</h2><blockquote><p><strong>Original rule</strong> &#8212; The use of pointers should be restricted. Specifically, no more than one level of dereferencing is allowed. Pointer dereference operations may not be hidden in macro definitions or inside typedef declarations. Function pointers are not permitted.</p></blockquote><p>Anybody who's done C beyond the basic examples will know the headache of pointers. It's like inception but with computer memory, you don't really know how deep you should follow the pointers.</p><p>The need for that is, by example, the <code>qsort()</code> function. You want to be able to sort any type of data but without knowing anything on them before compiling. Have a look at the signature:</p><pre><code>void qsort( void *ptr, size_t count, size_t size,
            int (*comp)(const void *, const void *) );</code></pre><p>It's one if the most frighteningly unsafe things you'll ever see in a standard library documentation. Yet, it allows the standard library to sort any kind of data, which other more modern language still have <a href="https://gobyexample.com/sorting">a little bit awkward</a> solutions.</p><p>But of course when you open the gate for this kind of things, you open the gate to any kind of pointer madness. And as you know, when a gate is open then people will go through it. Hence this rule for C.</p><p>However what about our case of interpreted languages? We will first cover why references are bad and then we will explain how to accomplish the initial intent of writing generic code.</p><h3>Don't use references</h3><p>Pointers don't exist but some ancient and obscure languages like <a href="https://www.php.net/manual/en/language.references.pass.php">PHP</a> still thought that it would be a good idea to have it. However, most of the other languages will only use a strategy named <a href="https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing">call-by-sharing</a>. The idea is &#8212; very quickly &#8212; that instead of passing a reference you will pass objects that can modify themselves.</p><p>The core point against references is that, beyond being memory unsafe and crazy in C, they also produce side-effects. By example, in PHP:</p><pre><code>function read($source, &amp;$n) {
    $content = // some way to get the content
    $n = // some way to get the read length

    return $content;
}

$n = 0;
$content = read("foo", $n);

print($n);</code></pre><p>That's a common, C-inspired, use-case for references. However, what you really want to do in this case is</p><pre><code>function read($source) {
    $content = // some way to get the content
    $n = // some way to get the read length

    return [$content, $n];
}

list($content, $n) = read("foo");

print($n);</code></pre><p>All you need is two return values instead of one. You can also return data objects which can fit any information you want them to fit and also evolve in the future without breaking existing code.</p><p>And all of this without affecting the scope of the calling function, which is rather nice.</p><p>Another safety point though is when you're modifying an object then you're potentially affecting the other users of that object. That's by example <a href="https://stackoverflow.com/questions/30979178/how-do-i-work-around-mutability-in-moment-js">a common pitfall of Moment.js</a>. Let's see.</p><pre><code>function add(obj, attr, value) {
    obj[attr] = (obj[attr] || 0) + value;
    return obj;
}

const a = {foo: 1};
const b = add(a, "foo", 1);

console.log(a.foo); // 2
console.log(b.foo); // 2</code></pre><p>On the other hand you can do:</p><pre><code>function add(obj, attr, value) {
    const patch = {};
    patch[attr] = (obj[attr] || 0) + value;
    return Object.assign({}, obj, patch);
}

const a = {foo: 1};
const b = add(a, "foo", 1);

console.log(a.foo); // 1
console.log(b.foo); // 2</code></pre><p>Both <code>a</code> and <code>b</code> stay distinct objects with distinct values because the <code>add()</code> function did a copy of <code>a</code> before returning it.</p><p>Let's conclude this already-too-long section with the final form of the rule:</p><blockquote><p>Don't mutate your arguments unless the explicit goal of your function is to mutate your arguments. If you do so, do it by sharing and not by reference.</p></blockquote><p>That would by example be the <a href="https://eslint.org/docs/rules/no-param-reassign">no-param-reassign</a> rule in ESLint as well as the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze">Object.freeze()</a> method. Or in Python you can use a <a href="https://docs.python.org/3/library/typing.html#typing.NamedTuple">NamedTuple</a> in many cases.</p><p>Note on performance: if you change the size of an object then the underlying process will basically be to allocate a new contiguous region of memory for it <a href="https://en.cppreference.com/w/c/memory/realloc">and then copy it</a>. For this reason, a mutation is often a copy anyways, so don't worry about copying your objects.</p><h3>Leverage the weak-ish dynamic typing</h3><p>Now that we closed the crazy door of references, we still need to write generic code if we want to stay <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRY</a>.</p><p>The good news is that while compiled languages are bound by the rules of physics and the way computers work, interpreted languages can have the luxury of putting a lot of additional support logic on top of that.</p><p>Specifically, they mostly rely on <a href="https://en.wikipedia.org/wiki/Duck_typing">duck typing</a>. Of course you can add some level of static type checking like <a href="https://www.typescriptlang.org/">TypeScript</a>, Python's <a href="https://docs.python.org/3/library/typing.html">type hints</a> or PHP's <a href="https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration">type declarations</a>. Using the wisdom of other rules:</p><ul><li><p>Rule 5 &#8212; Make many assertions. Expecting something from an object which doesn't actually have it will raise an exception, which you can catch and report.</p></li><li><p>Rule 10 &#8212; No warnings allowed (explained hereafter). Using the various type checking mechanisms you can rely on a static analyzer to help you spot errors that would arise at runtime.</p></li></ul><p>Those two rules will protect you from writing dangerous generic code. Which would result in the following rule</p><blockquote><p>You can write generic code as long as you use as many tools as possible to catch mistakes, and especially you need to follow rules 5 and 10.</p></blockquote><h2>10 &#8212; Compile with all possible warnings active; all warnings should then be addressed before release of the software.</h2><p>The initial full rule is:</p><blockquote><p>All code must be compiled, from the first day of development, with allcompiler warnings enabled at the compiler&#8217;s most pedantic setting. All code must compile with these setting without any warnings. All code must be checked daily with at least one, but preferably more than one, state-of-the-art static source code analyzer and should pass the analyses with zero warnings.</p></blockquote><p>Of course, interpreted code is not necessarily compiled so it's not about the compiler warnings <em>per se</em> but rather about getting the warnings.</p><p>There is fortunately a great amount of warning sources out there:</p><ul><li><p>All the <a href="https://www.jetbrains.com/idea/">JetBrains IDEs</a> are pretty awesome at finding out issues in your code. Recently, those IDE taught me a lot of patterns in different languages. That's really the main reason why I prefer something like this to a simplistic code editor: the warnings are very smart and helpful.</p></li><li><p>Linters for all the languages</p><ul><li><p>JavaScript &#8212; <a href="https://eslint.org/">eslint</a> with a set of rules <a href="https://github.com/airbnb/javascript">AirBnB</a> maybe?</p></li><li><p>Python &#8212; You can go full steam on <a href="https://github.com/astral-sh/ruff">Ruff</a> and pick the rules that suit you</p></li></ul></li><li><p>Automated code review tools like <a href="https://www.sonarqube.org/">SonarQube</a></p></li><li><p>Spell checkers are also surprisingly important because they will allow you to sniff out typos regardless of type analysis or any complicated static code analysis. It's a really efficient way to not lose hours because you typed <code>reuslts</code> instead of <code>results</code>.</p></li></ul><p>The main thing about warnings is that you <strong>must</strong> train your brain to see them. A single warning in the IDE will drive me mad while on the other hand I know people that just <em>won't see</em> them.</p><p>A final point on warnings is that on the contrary of compiled languages, warnings here are not always 100% certain. They are more like 95% certain and sometimes it's just an IDE bug. In that case, you should explicitly disable the warning and if possible give a small explanation of why you're sure that you don't need to apply this warning. However, think well before doing so because usually the IDE is right.</p><h2>Key takeaways</h2><p>The long discussion above tells us that those 10 rules were made for C and while you can use there philosophy in interpreted languages you can't really translate them into 10 other rules directly. Let's make our new power of 10 + 2 rules for interpreted languages.</p><ul><li><p><strong>Rule 1</strong> &#8212; Don't use <code>goto</code>, rationalize the use of <code>continue</code> and <code>break</code>, use <code>match</code> instead of <code>switch</code>.</p></li><li><p><strong>Rule 2</strong> &#8212; Prove that your problem can never create runaway code.</p></li><li><p><strong>Rule 3</strong> &#8212; To do so, limit the size of it. Usually using pagination, map/reduce, chunking, etc.</p></li><li><p><strong>Rule 4</strong> &#8212; Make code that fits in your head. If it fits in a page, it fits in your head.</p></li><li><p><strong>Rule 5</strong> &#8212; Check that things are right. Fail when wrong. Monitor failures. See rule 7.</p></li><li><p><strong>Rule 6</strong> &#8212; Don't use global-ish variables. Store data in the smallest possible scope.</p></li><li><p><strong>Rule 7</strong> &#8212; Let exceptions bubble up until you properly recover and/or report them.</p></li><li><p><strong>Rule 8</strong> &#8212; If you use transpilers, make sure that they solve more problems than they bring</p></li><li><p><strong>Rule 9.1</strong> &#8212; Don't use references even if your language supports it</p></li><li><p><strong>Rule 9.2</strong> &#8212; Copy arguments instead of mutating them, unless it's the explicit purpose of the function</p></li><li><p><strong>Rule 9.3</strong> &#8212; Use as many type-safety features as you can</p></li><li><p><strong>Rule 10</strong> &#8212; Use several linters and tools to analyze your code. No warning shall be ignored.</p></li></ul><p>And if you take a step back, all of those rules could be summed up in one rule to rule them all.</p><blockquote><p>Your computer, your RAM, your hard drive even your brain are bound by limits. You need to cut your problems, code and data into small boxes that will fit your computer, RAM, hard drive and brain. And that will fit together.</p></blockquote><p>&#8212; <em><s>Morpheus</s> Me</em></p><p>I consider that to be the core rule of programming and I apply it as an universal rationale to everything I do which is computer-related.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Baby CTO is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[Navigating the Tech Labyrinth: Welcome to Baby CTO!]]></title><description><![CDATA[Bridging Experience, Insight, and Passion for the Modern Tech Entrepreneur]]></description><link>https://www.baby-cto.com/p/navigating-the-tech-labyrinth-welcome</link><guid isPermaLink="false">https://www.baby-cto.com/p/navigating-the-tech-labyrinth-welcome</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Thu, 17 Aug 2023 11:12:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/87999a8f-579c-48c3-a743-2056bb780819_1312x928.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Greetings, tech enthusiasts and leaders!</p><p>Embarking on this new journey, Baby CTO is a culmination of diverse experiences, keen observations, and unwavering passion for the world of technology. If you're reading this, you've shown interest in diving deeper, and for that, I extend my heartfelt gratitude.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Baby CTO is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><strong>A Confluence of Cultures &amp; Skills:</strong><br>My background in telecommunications engineering from Telecom Lille 1 was just the beginning. The cultural nuances and tech landscapes of France, Spain, and India have enriched my understanding, granting me a holistic view of how technology integrates with varied societal fabrics.</p><p><strong>From Ventures to Valuable Lessons:</strong><br>Every attempt, be it my entrepreneurial endeavor into a next-generation travel guide or working with an eclectic mix of businesses at WITH, my tech agency, has been a stepping stone. While some ventures saw the sunset too soon, each provided invaluable insights into what truly works in the unpredictable realm of startups and technology.</p><p><strong>An Invitation to Engage:</strong><br>Baby CTO isn't just about sharing my stories. It's an open platform to discuss, debate, and delve into the intricacies of tech. From granular code insights to broad strategic reviews, the aim is to shed light on both the micro and macro aspects of our tech-driven world.</p><p><strong>The Road Ahead:</strong><br>This is just the beginning. With every post, we'll explore the labyrinthine corridors of the tech world, unveiling hidden insights, busting myths, and above all, learning together.</p><p>To each one of you who've taken a moment to subscribe, be it free or paid, know that you're the heartbeat of Baby CTO. Your support, feedback, and engagement are what will shape the future of this platform.</p><p>Join me, as we unravel the mysteries, celebrate the successes, and learn from the missteps in this dynamic world of technology. Welcome to Baby CTO, where our collective journey has just begun.</p><p>To tech and beyond!</p><p>Warmly,<br>R&#233;my</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Baby CTO is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</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[Coming soon]]></title><description><![CDATA[This is Baby CTO.]]></description><link>https://www.baby-cto.com/p/coming-soon</link><guid isPermaLink="false">https://www.baby-cto.com/p/coming-soon</guid><dc:creator><![CDATA[Rémy]]></dc:creator><pubDate>Thu, 17 Aug 2023 09:31:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!u3-p!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4c9d8fc-b387-47a4-b77f-c2aa0a303dc7_619x619.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is Baby CTO.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.baby-cto.com/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.baby-cto.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>