<?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[Building Apps for Startups with Ademar Tutor]]></title><description><![CDATA[Building Apps for Startups with Ruby on Rails, Hotwire & Turbo.]]></description><link>https://blog.ademartutor.com</link><image><url>https://substackcdn.com/image/fetch/$s_!QQJF!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa056aef0-c970-416f-b6a2-e229161db3b1_500x500.png</url><title>Building Apps for Startups with Ademar Tutor</title><link>https://blog.ademartutor.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 08 Apr 2026 16:51:41 GMT</lastBuildDate><atom:link href="https://blog.ademartutor.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Ademar Tutor]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[ademartutor@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[ademartutor@substack.com]]></itunes:email><itunes:name><![CDATA[Ademar Tutor]]></itunes:name></itunes:owner><itunes:author><![CDATA[Ademar Tutor]]></itunes:author><googleplay:owner><![CDATA[ademartutor@substack.com]]></googleplay:owner><googleplay:email><![CDATA[ademartutor@substack.com]]></googleplay:email><googleplay:author><![CDATA[Ademar Tutor]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Don't Remove the Human From the Loop. Give Them a Better Role.]]></title><description><![CDATA[How test-driven machine learning made AutoML usable for people with zero data science background]]></description><link>https://blog.ademartutor.com/p/dont-remove-the-human-from-the-loop</link><guid isPermaLink="false">https://blog.ademartutor.com/p/dont-remove-the-human-from-the-loop</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Fri, 03 Apr 2026 09:31:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!RTpW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Everyone&#8217;s talking about personal AI assistants right now, OpenClaw. And they&#8217;re genuinely useful. They write your emails, summarize your meetings, and plan your trips with a message from your phone.</p><p>But there&#8217;s a whole other side of AI that almost nobody talks about: using it to predict things. How many cups of coffee will you sell next week? <a href="https://blog.ademartutor.com/p/is-today-a-good-day-to-sell-coffee">Is it a good day to sell coffee? &#9749;&#65039; </a>Which customers are about to stop buying? Whether you should stock up on inventory or hold off. These are the kinds of decisions that business owners make on gut instinct every day, and AI can actually help with them.</p><p>The tools already exist. They&#8217;re called AutoML platforms. Basically, you plug in your business data, and the system builds a model that predicts sales, demand, churn, whatever matters to your business.</p><p>Not familiar? You&#8217;re not alone.</p><p>Researchers sat 16 regular people in front of one of these tools and tasked them to build a Machine Learning model. Not a single one could figure it out. These tools were built for data scientists, not the people who actually need them.</p><p>The irony is that building an ML model might feel foreign, but chances are you&#8217;re already using this exact technology every single day. You just don&#8217;t call it that.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qjko!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qjko!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 424w, https://substackcdn.com/image/fetch/$s_!Qjko!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 848w, https://substackcdn.com/image/fetch/$s_!Qjko!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 1272w, https://substackcdn.com/image/fetch/$s_!Qjko!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qjko!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png" width="228" height="494.1767441860465" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/de6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2796,&quot;width&quot;:1290,&quot;resizeWidth&quot;:228,&quot;bytes&quot;:993707,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.ademartutor.com/i/193050191?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.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_!Qjko!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 424w, https://substackcdn.com/image/fetch/$s_!Qjko!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 848w, https://substackcdn.com/image/fetch/$s_!Qjko!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 1272w, https://substackcdn.com/image/fetch/$s_!Qjko!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde6b097c-9a65-4cc0-a1d9-55a7fa40b34f_1290x2796.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When Spotify queues up a Discover Weekly playlist that somehow nails your mood. That&#8217;s a machine learning model trained on billions of listening patterns, predicting what you&#8217;ll want to hear next. When YouTube serves you an ad for running shoes, the week you started watching marathon training videos. That&#8217;s a prediction model matching your behavior to an advertiser&#8217;s audience. Even this post showing up in your feed right now? LinkedIn recently rebuilt its feed algorithm using large language models and transformer architectures, designed to understand what a post is actually about and match it to professional interests.</p><p>All of these are just Machine Learning (ML) models. Data goes in, patterns come out, and the system takes its best guess at what you&#8217;ll do next. The exciting part is that you can use the same tech to predict next week&#8217;s sales, spot customers who are about to churn, or figure out how many tomatoes to order for your sandwich shop using your own data to maximize your profit.</p><p>The tools to build <em>your own</em> ML models with machine learning already exist. Platforms like Azure ML, Google Vertex AI, and Amazon SageMaker all offer what the industry calls Automated Machine Learning. Think of it like this: if you want to forecast next month&#8217;s sales numbers or identify which customers are likely to stop using your service, these platforms let you do exactly that with your own data. The goal of these platforms is to let you avoid hiring a data scientist. Just upload your spreadsheet, press a button, and the system figures out the best ML model for you.</p><p>What actually happens is you upload your Excel file and immediately hit a wall. The system asks for your &#8220;target variable,&#8221; basically, what are you trying to predict? Maybe you are next week&#8217;s tomato sales. Then it wants to know if this is &#8220;regression&#8221; or &#8220;classification.&#8221; Translation: are you predicting a number (like sales), or a category (like yes/no)? Next up: pick an &#8220;evaluation metric.&#8221; RMSE, MAE, R&#178;&#8212;just different ways of measuring how close the predictions are to reality. You came in hoping to finally get a handle on your produce orders, and now you&#8217;re staring at a form that looks like it was built for a stats professor.</p><p>What actually happens is you upload your Excel file and immediately hit a wall. The system starts asking questions that sound like they belong in a university lecture. What is your &#8220;target variable,&#8221; &#8220;regression or classification,&#8221; &#8220;evaluation metric?&#8221;</p><p>If you&#8217;ve ever opened one of these platforms, seen that wall of options, and quietly closed the tab. Trust me, you&#8217;re not alone. A research team at Williams College ran a study where they sat 16 non-technical folks in front of these AutoML tools. No one could tell the system what they actually wanted it to do. Zero for sixteen.</p><p>But what&#8217;s actually interesting is how the researchers tried to fix it.</p><h2>The fix: make people do more, not less</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RTpW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RTpW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 424w, https://substackcdn.com/image/fetch/$s_!RTpW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 848w, https://substackcdn.com/image/fetch/$s_!RTpW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 1272w, https://substackcdn.com/image/fetch/$s_!RTpW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RTpW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png" width="1050" height="447" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:447,&quot;width&quot;:1050,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121378,&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://blog.ademartutor.com/i/193050191?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.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_!RTpW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 424w, https://substackcdn.com/image/fetch/$s_!RTpW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 848w, https://substackcdn.com/image/fetch/$s_!RTpW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 1272w, https://substackcdn.com/image/fetch/$s_!RTpW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50574496-23e1-4375-b33c-dd4b57bae5c6_1050x447.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The researchers built a system called CoAutoML, and its most interesting feature is the counterintuitive way we design systems and giving shortcuts to users, i.e. <a href="https://en.wikipedia.org/wiki/Three-click_rule">Three-click rule</a>. In CoAutoML, they actually gave more tasks to users.</p><p>Think of it like this: before CoAutoML builds anything, it asks you to write down a few real examples of what could happen. Imagine Spotify asking you to fill out a quick form before it builds your playlist.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Mycl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Mycl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png 424w, https://substackcdn.com/image/fetch/$s_!Mycl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png 848w, https://substackcdn.com/image/fetch/$s_!Mycl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png 1272w, https://substackcdn.com/image/fetch/$s_!Mycl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Mycl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png" width="1251" height="824" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:824,&quot;width&quot;:1251,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:174139,&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://blog.ademartutor.com/i/193050191?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.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_!Mycl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png 424w, https://substackcdn.com/image/fetch/$s_!Mycl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png 848w, https://substackcdn.com/image/fetch/$s_!Mycl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.png 1272w, https://substackcdn.com/image/fetch/$s_!Mycl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ed1bf89-7baf-47ad-95f5-8f09449b3093_1251x824.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>Instead of the system getting that info directly from your history, the system gets your expertise upfront. Context in, recommendation out.</p><p>Does not make sense to manually do that for your Spotify, right? But for building an ML model, it works really well.</p><h2>Test-Driven Machine Learning</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ff1I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ff1I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ff1I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ff1I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ff1I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ff1I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg" width="244" height="207" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:207,&quot;width&quot;:244,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7896,&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://blog.ademartutor.com/i/193050191?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.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_!ff1I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ff1I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ff1I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ff1I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5d49d5-9863-4998-af4f-93a75878dd6e_244x207.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>This idea is concept Test-Driven Machine Learning. Test-Driven ML is the practice of defining test cases before model building. No one had actually built it into a working tool (to the best of my knowledge) until CoAutoML was built to take the concept in front of real users.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tiSw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tiSw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 424w, https://substackcdn.com/image/fetch/$s_!tiSw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 848w, https://substackcdn.com/image/fetch/$s_!tiSw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 1272w, https://substackcdn.com/image/fetch/$s_!tiSw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tiSw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png" width="868" height="897" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:897,&quot;width&quot;:868,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:275654,&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://blog.ademartutor.com/i/193050191?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.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_!tiSw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 424w, https://substackcdn.com/image/fetch/$s_!tiSw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 848w, https://substackcdn.com/image/fetch/$s_!tiSw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 1272w, https://substackcdn.com/image/fetch/$s_!tiSw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d4f503c-d9a8-449f-a9c4-b503d71c2aef_868x897.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>What happened when real people used it</h2><p>The results were striking.</p><p>Participants started using tactile, embodied language to describe the experience. One said it felt like &#8220;being hands-on with the data&#8230; like touching the data.&#8221; Another said that the standard evaluation metrics meant nothing to them, but seeing their own expected output next to the model&#8217;s predicted output made everything clear. Seeing that they&#8217;d predicted 3.6 and the model predicted 3.58 gave them an intuitive grasp of model performance that no accuracy score ever could.</p><p>Even better, people started poking around. They&#8217;d try out extreme values just to see what happened. They&#8217;d spot patterns in their own data they&#8217;d never noticed before. Something they said they never would have caught if the system just did everything behind the scenes. If there were just a button that did it all, they never would have seen it.</p><p>The system didn&#8217;t teach these people machine learning. It gave them a way to express what they already knew, which was their domain expertise, in a format the machine could use.</p><p>By the end, participants reported high confidence in their ability to do ML tasks independently using the tool. Not because they suddenly understood gradient boosting, but because the interface matched the way they already thought about the problem: data goes in, a prediction comes out, and I can check whether it makes sense.</p><h2>What this means if you&#8217;re building AI agents for data work</h2><p>This is the part that matters if you&#8217;re thinking about agentic data teams, which, honestly, is what I spend most of my time on these days.</p><p>Most people in the AutoML and AI agent world assume the goal is total automation. Remove the human. Make it seamless. But this research points to something different: the best systems aren&#8217;t the ones that do everything for you. They&#8217;re the ones that ask you the right questions at the right time, in words you actually understand.</p><p>For SMEs without data teams, this distinction is critical. When you&#8217;re building AI agents that handle data pipelines, analysis, and reporting for a small company, you can&#8217;t assume the person on the other end knows what a &#8220;target variable&#8221; is. But you also can&#8217;t just hide everything behind a black box, because then they won&#8217;t trust the output or act on it.</p><p>The CoAutoML research points to a middle path: give people a role that matches how they already think. Don&#8217;t ask them to be data scientists. Let them say what they know in their own words, and let the system handle the translation into whatever the ML pipeline needs. Ask them to be domain experts, which they already are!</p><p></p><div><hr></div><p><em>Starkova, V. &amp; Howley, I. (2026). CoAutoML: User Interface Framework for Machine Learning Novices using LLM-based AutoML and Test-Driven Machine Teaching. IUI '26, Paphos, Cyprus. <a href="https://doi.org/10.1145/3742413.3789153">doi.org/10.1145/3742413.3789153</a></em></p>]]></content:encoded></item><item><title><![CDATA[AI agents work better when you give them less freedom]]></title><description><![CDATA[A neuroscience paper showed me how to build better AI data teams for businesses.]]></description><link>https://blog.ademartutor.com/p/ai-agents-work-better-when-you-give</link><guid isPermaLink="false">https://blog.ademartutor.com/p/ai-agents-work-better-when-you-give</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Tue, 24 Mar 2026 00:50:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3R98!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You&#8217;ve probably had this experience: you ask ChatGPT to write a report based on some spreadsheets you pulled from the finance department. It gives you something that looks right, but when you actually read the details, it gives you a beautiful answer to a question you didn&#8217;t ask. It makes up column names.</p><p>Now imagine that happening inside an automated data pipeline run by AI agents. At 2am. With no one watching.</p><p>This is the main issue in building AI agents that actually do useful work for companies. The same flexibility that makes LLMs impressive is exactly what makes them dangerous when you need reliability.</p><p>A research group at <a href="https://www.epfl.ch/en/">EPFL</a> built a system called <a href="https://www.mackenziemathislab.org/amadeusgpt">AmadeusGPT</a> in 2023. It analyzes animal behavior in neuroscience labs using natural language. On the surface, it has nothing to do with business. But it shows something important: <strong>AI agents become more reliable when you give them less autonomy, not more.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3R98!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3R98!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 424w, https://substackcdn.com/image/fetch/$s_!3R98!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 848w, https://substackcdn.com/image/fetch/$s_!3R98!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 1272w, https://substackcdn.com/image/fetch/$s_!3R98!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3R98!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png" width="1456" height="651" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:651,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:495106,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.ademartutor.com/i/191922887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.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_!3R98!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 424w, https://substackcdn.com/image/fetch/$s_!3R98!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 848w, https://substackcdn.com/image/fetch/$s_!3R98!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 1272w, https://substackcdn.com/image/fetch/$s_!3R98!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8ac4c1b-d85f-40ca-92bb-627374cba143_1539x688.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>What the researchers actually built</h2><p>The EPFL team faced a problem that should sound familiar. Labs generate piles of video data, such as mice running through mazes or horses on treadmills. Analyzing that data means stitching together pretrained models like DeepLabCut for animal trs Segment Anything for object segmentation, etc. These are&#8217; etc. These are work that traditionally requires coding scripts, training models, or integrating multiple codebases. <strong>The problem is that people who understand biology often can&#8217;t code, and the people who can code often don&#8217;t understand the biology.</strong></p><p>Sound familiar? Swap &#8220;biology&#8221; for &#8220;your business domain&#8221; and &#8220;video data&#8221; for &#8220;your sales pipeline,&#8221; and you&#8217;ve got the exact problem most SMEs face with their data.</p><p>Their solution was to put GPT-3.5 in charge of writing and executing the analysis code based on plain language questions from researchers. A scientist could type &#8220;When is the mouse on the treadmill?&#8221; and the system would determine which models to run, generate the Python code, execute it, and return the answer.</p><p>But here&#8217;s the part that matters: <strong>they didn&#8217;t just point ChatGPT at the problem and hope for the best.</strong> They built a system of constraints and supporting components around it. And those constraints are what made it work.</p><h2>The orchestration lesson</h2><p>The researchers identified four reasons why a raw LLM can&#8217;t reliably do this kind of work: (1) it doesn&#8217;t know your private tools and APIs, (2) it hallucinates functions when given too much implementation detail, (3) it runs out of context window on complex tasks.</p><p>Now, to be fair: context windows have grown 30x since this paper. GPT-3.5 had a 4,096 token limit; today we&#8217;re talking 128K&#8211;200K+. That specific constraint is fading. But the other three problems haven&#8217;t gone anywhere. The (2) model still hallucinates functions, (1) still doesn&#8217;t know your private tools. And ironically, (3) bigger context windows introduce their own issues. Models get distracted by irrelevant context, and costs scale with the number of tokens. The architectural lesson isn&#8217;t about token limits. It&#8217;s about how constraint and orchestration outperformed raw capability. That finding becomes even <em>more</em> relevant as models become more powerful.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vlri!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vlri!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png 424w, https://substackcdn.com/image/fetch/$s_!vlri!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png 848w, https://substackcdn.com/image/fetch/$s_!vlri!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png 1272w, https://substackcdn.com/image/fetch/$s_!vlri!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vlri!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png" width="623" height="455" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b175db60-d381-4241-84f5-678433ae9ca1_623x455.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:455,&quot;width&quot;:623,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37581,&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://blog.ademartutor.com/i/191922887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.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_!vlri!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png 424w, https://substackcdn.com/image/fetch/$s_!vlri!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png 848w, https://substackcdn.com/image/fetch/$s_!vlri!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.png 1272w, https://substackcdn.com/image/fetch/$s_!vlri!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb175db60-d381-4241-84f5-678433ae9ca1_623x455.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">Major model releases (GPT-4, Claude, Gemini) are overlaid to illustrate the rapid escalation in context capacity from thousands to millions of tokens. Notably, the largest jumps (Claude 2, GPT-4 Turbo, Gemini 1.5) correspond to shifts in architectural strategy toward long-context handling, yet do not inherently resolve reliability challenges in complex task execution.</figcaption></figure></div><p></p><p>Their fix was architectural, not just a better prompt. And the single most important design decision was this: <strong>they hid the implementation and only showed the interface.</strong></p><p>Instead of feeding GPT the full source code of their analysis tools (hundreds of lines of Python per function) they gave it only the function documentation. What each function does, what it accepts, what it returns. Nothing else. It&#8217;s like giving a new employee a clear job description instead of dumping the entire company codebase on their desk.</p><h2>The architecture</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YHwn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YHwn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 424w, https://substackcdn.com/image/fetch/$s_!YHwn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 848w, https://substackcdn.com/image/fetch/$s_!YHwn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 1272w, https://substackcdn.com/image/fetch/$s_!YHwn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YHwn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png" width="1456" height="1070" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1070,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:985504,&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://blog.ademartutor.com/i/191922887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.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_!YHwn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 424w, https://substackcdn.com/image/fetch/$s_!YHwn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 848w, https://substackcdn.com/image/fetch/$s_!YHwn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 1272w, https://substackcdn.com/image/fetch/$s_!YHwn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff495f713-35ad-451e-a707-3c75d0db16ee_5446x4003.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Here&#8217;s how they did it.</p><h4><strong>Step 1: Register only the interface, never the implementation.</strong> </h4><p>A Python decorator (<a href="https://github.com/AdaptiveMotorControlLab/AmadeusGPT/blob/main/amadeusgpt/programs/api_registry.py">@register_core_api</a>) captures only three things about each function: its name, its parameter types, and its docstring. The actual logic is discarded at the point of registration.</p><p>python</p><pre><code>CORE_API_REGISTRY[func.__name__] = {    
  &#8220;name&#8221;: func.__name__,
  &#8220;parameters&#8221;: inputs,        # type annotations only
  &#8220;description&#8221;: func.__doc__,  # docstring only
}</code></pre><p></p><h4><strong>Step 2: Format those registrations as documentation for GPT.</strong> </h4><p>A separate function (<a href="https://github.com/AdaptiveMotorControlLab/AmadeusGPT/blob/main/amadeusgpt/programs/sandbox.py">get_core_api_docs()</a>) converts the registry into a clean, readable spec block. They are just function signatures and descriptions. No source code. Just the &#8220;job description.&#8221;</p><h4><strong>Step 3: Inject that documentation into the system prompt.</strong> </h4><p>The <a href="https://github.com/AdaptiveMotorControlLab/AmadeusGPT/blob/main/amadeusgpt/system_prompts/code_generator.py">code generator prompt</a> explicitly tells GPT: <code>&#8220;This block contains information about the core APIs... They do not contain implementation details but you can use them to write code.&#8221;</code></p><h4><strong>Step 4: GPT generates code using only the interface.</strong> </h4><p>GPT sees signatures like <code>get_animals_animals_events(cross_animal_query_list, bodypart_names, ...)</code> with their docstrings, and writes code that calls these functions &#8212; without ever seeing the implementation behind each one. The real work happens in manager classes (<a href="https://github.com/AdaptiveMotorControlLab/AmadeusGPT/blob/main/amadeusgpt/managers/animal_manager.py">animal_manager.py</a>, <a href="https://github.com/AdaptiveMotorControlLab/AmadeusGPT/blob/main/amadeusgpt/managers/object_manager.py">object_manager.py</a>, etc.) that GPT never touches.</p><h4>The result: </h4><p>GPT stopped inventing functions that didn&#8217;t exist. Token usage dropped because less context was needed. The system produced correct, executable code from plain English questions.</p><p>On a standardised animal behavior benchmark (<a href="https://arxiv.org/abs/2207.10553">MABe 2022 Behavior Challenge</a>), this constrained system matched or outperformed dedicated machine learning models that had been specifically trained for the task. And with GPT-4 instead of GPT-3.5, the error rate on real user queries dropped from 18% to 10%. </p><h2>What this means if you&#8217;re building (or buying) AI for your data</h2><p>Here&#8217;s where this connects to what I think about every day: <br><strong>building agentic data teams for SMEs.</strong></p><p>Most of the AI hype you hear is about making models bigger, more capable, more autonomous. The promise is: just give the AI more freedom, and it&#8217;ll figure it out. But this paper demonstrates the opposite. The magic was in the constraints. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x6nM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x6nM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!x6nM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!x6nM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!x6nM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x6nM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png" width="434" height="434" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1200,&quot;width&quot;:1200,&quot;resizeWidth&quot;:434,&quot;bytes&quot;:1004905,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.ademartutor.com/i/191922887?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.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_!x6nM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!x6nM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!x6nM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!x6nM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1be48801-0d87-4297-9ff6-5ef7fb26a31c_1200x1200.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 maps directly to what I&#8217;ve learned from years of running engineering teams. The bottleneck in delivery is never talent. It&#8217;s orchestration. The handoffs, the QA loops, the &#8220;who checks if this works with our X number of existing features&#8221; problem. When you get the coordination right, a small team outperforms a big one. That&#8217;s true whether the team is human or artificial.</p><h2>The takeaway</h2><p>AmadeusGPT offers a crucial lesson for any business bringing AI into its data operations:</p><h4>Design the interfaces your AI agents work through as carefully as you would design a job description for a new hire.</h4><p></p><p>Define what each function does, what it accepts, and what it returns. Hide the rest. The narrower the surface area, the fewer ways the agent can be wrong.</p><p>And that principle extends beyond APIs. The researchers didn&#8217;t build one super-agent that did everything. They built a system of components with specific roles. A code generator agent, a rephraser agent, a self-correction agent, and an explainer agent. Each one had a narrow job and a clean interface to the others. Your agentic team should work the same way: one agent writes the query, another validates it, another explains the results.</p><p>They also planned for failure. The self-correction mechanism in AmadeusGPT didn&#8217;t prevent all errors, but it caught a significant number of them without human intervention. Good orchestration is not assuming that the first attempt will be perfect. It means building in checkpoints, retries, and graceful failure.</p><h2>The Bottom line</h2><p>The companies that will get the most value from AI in the next few years won&#8217;t be the ones using the most powerful models. They&#8217;ll be the ones who orchestrate AI agents most effectively with the right constraints, the right memory, and the right coordination among agents.</p><div><hr></div><p><em>Paper: Ye, S., Lauer, J., Zhou, M., Mathis, A., &amp; Mathis, M.W. (2023). AmadeusGPT: a natural language interface for interactive animal behavioral analysis. NeurIPS 2023.</em></p><div><hr></div><p><em>Hello, I&#8217;m Ademar Tutor. I&#8217;m researching how to agentic data teams for SMEs. An AI system that delivers the data capabilities of a full data team, without the headcount. I&#8217;m currently completing my Master&#8217;s in AI at the University of Waikato. I share what I&#8217;m learning along the way! Follow me on <a href="https://www.linkedin.com/in/ademar-tutor-0a95972a/">LinkedIn</a> if that&#8217;s a problem you&#8217;re thinking about too.</em></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Deploying a full-stack LLM judge system on Azure Container Apps]]></title><description><![CDATA[I wanted to deploy the LLM-as-a-Judge I recently developed.]]></description><link>https://blog.ademartutor.com/p/deploying-a-full-stack-llm-judge</link><guid isPermaLink="false">https://blog.ademartutor.com/p/deploying-a-full-stack-llm-judge</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Fri, 30 Jan 2026 02:26:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Sz_0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I wanted to deploy the <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach">LLM-as-a-Judge</a> I recently developed. I want to deploy a:</p><ul><li><p>Front-end: Next.js</p></li><li><p>Back-end: FastAPI</p></li><li><p>LLM integration: LangChain</p></li></ul><p>I wanted a really easy way to deploy the app without handling too much of the config, similar to Heroku, Vercel, or Fly.io, but without the heavy lifting. </p><p>That&#8217;s when I stumbled on <strong>Azure Container Apps</strong>.</p><p>In this post, I&#8217;ll walk through what I learned deploying an AI evaluation system on Azure Container Apps and why this architecture is a surprisingly good fit if you&#8217;re building AI systems without a dedicated DevOps team.</p><h2>A Quick Primer: AKS vs. Azure Container Apps</h2><p><strong>Azure Kubernetes Service (AKS)</strong> is Microsoft&#8217;s managed Kubernetes offering. Kubernetes itself is the industry-standard container orchestration platform. It handles deploying, scaling, and managing containerized applications across clusters of machines. &#8220;Managed&#8221; means Azure handles the control plane (the brain of the cluster), but you still manage worker nodes, networking, upgrades, and the endless YAML configuration that Kubernetes requires. AKS is powerful and flexible, which is why large engineering teams love it. But that power comes with complexity.</p><p><strong>Azure Container Apps</strong> is a higher-level abstraction built on top of Kubernetes. The key difference: you never see or touch the Kubernetes layer. You give Azure your containers, tell it how you want them to scale and communicate, and it handles everything else: node management, networking, certificate rotation, cluster upgrades. You get the benefits of container orchestration (revisions, traffic splitting, autoscaling, managed ingress) without writing a single Kubernetes manifest.</p><p>Think of it this way: AKS gives you a fully-equipped commercial kitchen where you control every burner and oven. Container Apps gives you a meal delivery service; you provide the recipes (containers), and someone else handles the cooking infrastructure.</p><p>For solo builders and small teams, that tradeoff matters enormously.</p><h2>Architecture Overview</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sz_0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sz_0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png 424w, https://substackcdn.com/image/fetch/$s_!Sz_0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png 848w, https://substackcdn.com/image/fetch/$s_!Sz_0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png 1272w, https://substackcdn.com/image/fetch/$s_!Sz_0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sz_0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png" width="188" height="549.0370370370371" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3706,&quot;width&quot;:1269,&quot;resizeWidth&quot;:188,&quot;bytes&quot;:225259,&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://blog.ademartutor.com/i/185190620?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.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_!Sz_0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png 424w, https://substackcdn.com/image/fetch/$s_!Sz_0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png 848w, https://substackcdn.com/image/fetch/$s_!Sz_0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.png 1272w, https://substackcdn.com/image/fetch/$s_!Sz_0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07c8c526-c5cb-4afc-974d-d4c23d58e122_1269x3706.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>Three containers, one environment, zero Kubernetes manifests.</p><p>Let me run you through how I set this up.</p><h2>Step-by-Step: First-Time Setup</h2><p>Throughout this tutorial, replace these placeholders with your own values:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{array}{|l|l|l|}\n\\hline\n\\textbf{Placeholder} &amp; \\textbf{Description} &amp; \\textbf{Example} \\\\\n\\hline\n\\texttt{<your-app>} &amp;\n\\text{Your application name (used for resource naming)} &amp;\n\\texttt{myapp, llm-judge, eval-system} \\\\\n\\hline\n\\texttt{<youracr>} &amp;\n\\text{Your Azure Container Registry name (alphanumeric only, globally unique)} &amp;\n\\texttt{myappregistry, llmjudgeacr} \\\\\n\\hline\n\\texttt{<env-suffix>} &amp;\n\\text{Auto-generated suffix from Azure (shown after first deploy)} &amp;\n\\texttt{delightfulocean-abc123} \\\\\n\\hline\n\\texttt{<db-user>} &amp;\n\\text{Your database username} &amp;\n\\texttt{appuser} \\\\\n\\hline\n\\texttt{<db-password>} &amp;\n\\text{Your database password} &amp;\n\\texttt{securepassword123} \\\\\n\\hline\n\\texttt{<db-name>} &amp;\n\\text{Your database name} &amp;\n\\texttt{app_db} \\\\\n\\hline\n\\end{array}\n&quot;,&quot;id&quot;:&quot;DEKFOJMJCL&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><h3>1. Create a resource group</h3><pre><code>az group create \
  --name &lt;your-app&gt;-rg \
  --location southeastasia</code></pre><h3>2. Create a Container Apps environment</h3><pre><code>az containerapp env create \
  --name &lt;your-app&gt;-env \
  --resource-group &lt;your-app&gt;-rg \
  --location southeastasia</code></pre><h3>3. Build Docker images for linux/amd64</h3><p>If you're on Apple Silicon, this step matters. Azure runs amd64, so you need to build for that architecture explicitly, otherwise feel free to skip this step:</p><pre><code>docker build \
  --platform linux/amd64 \
  -t &lt;your-app&gt;-backend:latest \
  ./backend

docker build \
  --platform linux/amd64 \
  -t &lt;your-app&gt;-frontend:latest \
  ./frontend</code></pre><h3>4. Create Azure Container Registry</h3><pre><code>az acr create \
  --resource-group &lt;your-app&gt;-rg \
  --name &lt;youracr&gt; \
  --sku Basic \
  --admin-enabled true</code></pre><p><em><strong>Note:</strong> ACR names must be globally unique and contain only alphanumeric characters (no hyphens).</em></p><p></p><h3>5. Login, tag, and push</h3><pre><code>az acr login --name &lt;youracr&gt;

docker tag &lt;your-app&gt;-backend:latest &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-backend:latest
docker tag &lt;your-app&gt;-frontend:latest &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-frontend:latest

docker push &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-backend:latest
docker push &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-frontend:latest</code></pre><p>When it finishes, Azure prints your public URLs:</p><ul><li><p>https://backend.&lt;suffix&gt;.southeastasia.azurecontainerapps.io/</p></li><li><p>https://frontend.&lt;suffix&gt;.southeastasia.azurecontainerapps.io/</p></li></ul><p></p><h2>What You'll Run Daily</h2><p>Once the infrastructure is setup, every subsequent deploy can be done on a single script deploy-demo.sh. Here&#8217;s a run-down of what the script does:</p><h3>Step 1: Build images with the backend URL baked in</h3><pre><code>docker build --platform linux/amd64 -t &lt;your-app&gt;-backend:latest ./backend

docker build --platform linux/amd64 \
  --build-arg NEXT_PUBLIC_API_BASE=https://backend.&lt;env-suffix&gt;.azurecontainerapps.io \
  -t &lt;your-app&gt;-frontend:latest ./frontend</code></pre><p>That <code>NEXT_PUBLIC_API_BASE</code> argument matters. Next.js compiles environment variables prefixed with <code>NEXT_PUBLIC_</code> into the browser bundle at build time. If you don't set it here, your frontend won't know where to find your backend.</p><h3>Step 2: Push to the registry</h3><pre><code>docker tag &lt;your-app&gt;-backend:latest &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-backend:latest
docker tag &lt;your-app&gt;-frontend:latest &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-frontend:latest

docker push &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-backend:latest
docker push &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-frontend:latest</code></pre><h3>Step 3: Update the container apps</h3><pre><code>az containerapp update \
  --name backend \
  --resource-group &lt;your-app&gt;-rg \
  --image &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-backend:latest

az containerapp update \
  --name frontend \
  --resource-group &lt;your-app&gt;-rg \
  --image &lt;youracr&gt;.azurecr.io/&lt;your-app&gt;-frontend:latest</code></pre><p>Each <code>update</code> command creates a new revision. The new revision starts receiving traffic automatically. If something breaks, you can route traffic back to the previous revision with one command.</p><h3>Step 4: Patch environment variables</h3><pre><code>FRONTEND_FQDN=$(az containerapp show --name frontend --resource-group &lt;your-app&gt;-rg --query "properties.configuration.ingress.fqdn" -o tsv)

az containerapp update \
  --name backend \
  --resource-group &lt;your-app&gt;-rg \
  --set-env-vars \
    FRONTEND_URL=https://${FRONTEND_FQDN} \
    DATABASE_URL=postgresql+psycopg2://&lt;db-user&gt;:&lt;db-password&gt;@db:5432/&lt;db-name&gt; \
    ENV=production</code></pre><p><em>Note that </em><code>DATABASE_URL</code><em> points to </em><code>db</code><em>, the internal service name. Your Postgres instance isn't exposed to the internet, only your backend can reach it.</em></p><p>The complete loop</p><pre><code>./deploy-demo.sh
  &#8594; builds amd64 images
  &#8594; pushes to ACR
  &#8594; updates container apps (creates new revisions)
  &#8594; patches environment variables
  &#8594; done</code></pre><p>Note:</p><p>I&#8217;ve experience a few times wherein sometimes the script does not work. This happens terminal has been open for days. Run these two commands and retry:</p><pre><code>az login
az acr login --name &lt;youracr&gt;</code></pre><p></p><h2>Conclusion</h2><p>Azure Container Apps isn&#8217;t &#8220;AKS lite.&#8221; It&#8217;s a different tradeoff entirely: you give up control over the orchestration layer, and in exchange, you get to focus on your actual product. And for my use case, Azure Container Apps fits the bill.</p><div><hr></div><p><em>If you&#8217;re building something similar and want to compare notes, I&#8217;d like to hear about it. What&#8217;s your current deploy setup, and what&#8217;s painful about it?</em></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Prompt templates evaluation contracts]]></title><description><![CDATA[Versioned rubrics in the database]]></description><link>https://blog.ademartutor.com/p/prompt-templates-evaluation-contracts</link><guid isPermaLink="false">https://blog.ademartutor.com/p/prompt-templates-evaluation-contracts</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Thu, 22 Jan 2026 02:02:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_WFm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h6><strong>Who this is for:</strong></h6><ul><li><p>Engineers building LLM-as-a-Judge or LLM evaluation pipelines</p></li><li><p>MLOps/Platform teams who need audit trails for AI outputs</p></li><li><p>Tech leads evaluating how to manage prompt configuration at scale</p></li></ul><h6><strong>What you&#8217;ll get:</strong></h6><ul><li><p>A concrete database pattern (Postgres + SQLAlchemy) for versioned prompt templates</p></li><li><p>API design for tenant-scoped prompt activation</p></li><li><p>An audit trail that links every assessment to its prompt version</p></li></ul><div><hr></div><p>I previously thought that &#8220;LLM apps are just prompts + glue.&#8221; Basically, they are just &#8220;LLM Wrappers.&#8221;</p><p>After building a few LLM apps, I disagree. The prompt isn&#8217;t copywriting. It&#8217;s a <strong>production configuration</strong>.</p><p>If your prompt changes, your system behavior changes. If your system behavior changes, your evaluation metrics shift. And if your evaluation shifts without an audit trail, you end up &#8220;improving&#8221; the product by accident because you changed the yardstick, not the thing being measured.</p><h2><strong>What happens when there is no prompt versioning?</strong></h2><p>Teams burn entire sprints chasing phantom regressions. Scores drop 15% after a &#8220;minor tweak.&#8221; Was the tweak the model, the data, or the prompt? Nobody knows, because nobody recorded which prompt produced which assessment.</p><p><a href="https://aman.ai/primers/ai/LLM-as-a-judge/">Research on LLM-as-a-Judge</a> systems shows that even small prompt variations can significantly affect scores, rankings, and bias characteristics, introducing what researchers call &#8220;evaluation instability driven by prompt mis-specification rather than model capability.&#8221;</p><p><a href="https://arxiv.org/abs/2410.12405">A 2024 EMNLP study</a> found that LLM performance is highly sensitive to the prompts utilized, and this variability poses challenges for accurate assessment.</p><p>Meanwhile, scoring bias and prompt sensitivity <a href="https://www.emergentmind.com/topics/llm-based-judge-model">studies</a> show that even state-of-the-art judges can have large per-instance score variance under simple prompt perturbations like rubric order or score anchoring.</p><p>If you&#8217;re using LLM-as-a-Judge in production, you&#8217;re one undocumented prompt edit away from:</p><ul><li><p><strong>Unexplainable metric shifts</strong> that erode stakeholder trust</p></li><li><p><strong>Compliance gaps</strong> when auditors ask for evaluation lineage</p></li><li><p><strong>Wasted debugging cycles</strong> because you can&#8217;t isolate variables</p></li><li><p><strong>False confidence</strong> in &#8220;improvements&#8221; that were just measurement drift</p></li></ul><p>That&#8217;s why modern teams treat prompts as <strong>versioned contracts</strong> and store them like contracts: in a database and recorded on every evaluation artifact. This fits the broader shift toward product-level evaluation (not &#8220;model vibes&#8221;) that&#8217;s showing up in <a href="https://medium.com/%40QuarkAndCode/llm-evaluation-in-2025-metrics-rag-llm-as-judge-best-practices-ad2872cfa7cb?utm_source=chatgpt.com">2025 eval playbooks</a>.</p><p><strong>Is this post for you?</strong></p><p>Ask yourself:</p><ul><li><p>Have you ever shipped a prompt change and couldn&#8217;t explain why scores shifted?</p></li><li><p>Do you store prompts in code but have no record of which version produced which output?</p></li><li><p>Are different customers (or tenants) asking for different evaluation criteria and you&#8217;re copy-pasting prompts to handle it?</p></li><li><p>Could you answer, right now, &#8220;which prompt version generated this assessment 3 months ago?&#8221;</p></li></ul><p>If any of these hit home, keep reading. This post breaks down a concrete pattern from the app I&#8217;ve built<a href="https://github.com/iamademar/llm-as-a-judge-sales-coach"> </a><strong><a href="https://github.com/iamademar/llm-as-a-judge-sales-coach">llm-as-a-judge-sales-coach</a> </strong>(multi-tenant &#8220;LLM as an evaluator&#8221; app for <strong>sales coaching</strong>.):</p><blockquote><p><strong>Prompt templates as evaluation contracts:</strong> versioned rubrics stored in Postgres, with an &#8220;active template per org&#8221; and an assessment audit trail that records prompt version.</p></blockquote><h2>Why is &#8220;prompt templates as contracts&#8221; trending?</h2><p>LLM evaluation is prompt-sensitive. A small rubric tweak can swing agreement metrics or produce systematically different &#8220;judgments.&#8221; Surveys and platform docs now call out <strong>prompt templates</strong> as a key driver of bias/variance in LLM-as-judge evaluation, <a href="https://arxiv.org/html/2412.05579v2">which is why teams increasingly treat evaluation prompts as managed artifacts.</a></p><p>The goal is:</p><ol><li><p><strong>Version</strong> the prompt like a contract (v0, v1, &#8230;)</p></li><li><p><strong>Activate</strong> exactly one contract per tenant</p></li><li><p><strong>Record</strong> which contract produced each assessment</p></li><li><p><strong>Evaluate</strong> changes offline before promoting them</p></li></ol><p>That&#8217;s what this implementation does.</p><h2>The pattern: prompt templates as a first-class database model</h2><p>In the app, a prompt template is a row in prompt_templates:</p><ul><li><p>organization_id (tenant boundary)</p></li><li><p>name</p></li><li><p>version (e.g., v0, v1, custom_v2)</p></li><li><p>system_prompt</p></li><li><p>user_template (must contain {transcript})</p></li><li><p>is_active (only one active per org)</p></li></ul><p>The model is explicit about the &#8220;one active per org&#8221; invariant:</p><pre><code>class PromptTemplate(Base):

    """

    Only one template per organization can be active at a time.

    """

    version = Column(String(20), nullable=False, default=&#8221;v0&#8221;)

    is_active = Column(Boolean, default=False, server_default=&#8221;false&#8221;, nullable=False)</code></pre><p>Full Source: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/models/prompt_template.py">backend/app/models/prompt_template.py</a></p><h2>Contract enforcement: &#8220;active template per org&#8221;</h2><p>This is where the pattern truly shines.</p><p>When you create or update a template with is_active=True, the CRUD layer <strong>deactivates all other templates for that org</strong>:</p><pre><code>def _deactivate_org_templates(db, organization_id):

    db.query(PromptTemplate).filter(

        PromptTemplate.organization_id == organization_id,

        PromptTemplate.is_active == True,

    ).update({&#8221;is_active&#8221;: False})

def create(..., is_active=False):

    if is_active:

        _deactivate_org_templates(db, organization_id)

    ...</code></pre><p>Full Source: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/crud/prompt_template.py">backend/app/crud/prompt_template.py</a></p><p>That gives you a clean tenant-safe guarantee:</p><ul><li><p>each org can iterate on prompts independently</p></li><li><p>the runtime scorer always has a single &#8220;source of truth&#8221;</p></li><li><p>rollbacks become easy: just re-activate the prior version</p></li></ul><p>The API exposes this in a very &#8220;config management&#8221; way:</p><ul><li><p>GET /prompt-templates/active &#8594; fetch the active contract</p></li><li><p>POST /prompt-templates/{template_id}/activate &#8594; promote a version</p></li></ul><pre><code>@router.get(&#8221;/active&#8221;)

def get_active_template(...):

    template = template_crud.get_active_for_org(db, org_id)

    ...

@router.post(&#8221;/{template_id}/activate&#8221;)

def activate_template(...):

    updated = template_crud.update(db, template, is_active=True)</code></pre><p>Full source:  <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/routers/prompt_templates.py">backend/app/routers/prompt_templates.py</a></p><p></p><h2>The default contract: hardcoded v0, persisted at org creation</h2><p>You still want a sane default so the system works on day one.</p><p>This repo keeps the initial prompt as code constants:</p><ul><li><p>SYSTEM (role + strict rules)</p></li><li><p>USER_TEMPLATE (JSON schema + {transcript} insertion)</p></li></ul><pre><code>def create_default_for_org(db, organization_id):

    from app.prompts.prompt_templates import SYSTEM, USER_TEMPLATE

    return create(..., version=&#8221;v0&#8221;, system_prompt=SYSTEM, user_template=USER_TEMPLATE, is_active=True)</code></pre><p>Full source: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/crud/prompt_template.py">backend/app/crud/prompt_template.py</a></p><p></p><p>And the user template makes the &#8220;contract&#8221; concrete by embedding a strict JSON schema and requiring the transcript placeholder:</p><pre><code>CONVERSATION TRANSCRIPT:

{transcript}

Provide your assessment as valid JSON matching the schema above.</code></pre><p>Full source: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/prompts/prompt_templates.py">backend/app/prompts/prompt_templates.py</a></p><h2>Auditability: template version recorded with each assessment</h2><p>This is the &#8220;evaluation contract&#8221; payoff.</p><p>The scoring pipeline returns (assessment_data, model_name, prompt_version):</p><pre><code>template = get_active_template(...)

system, user = build_prompt(..., system_prompt=template.system_prompt, user_template=template.user_template)

prompt_version = template.version

...

return assessment_data, model_name, prompt_version</code></pre><p>Full source: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/services/scorer.py">backend/app/services/scorer.py</a></p><p>Then the /assess router persists that prompt version on the Assessment record:</p><pre><code>data, model_name, prompt_ver = score_transcript(...)

assessment = Assessment(
  transcript_id=transcript.id,
  scores=data[&#8221;scores&#8221;],
  coaching=data[&#8221;coaching&#8221;],
  model_name=model_name,
  prompt_version=prompt_ver,
)</code></pre><p>Full source: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/routers/assess.py">backend/app/routers/assess.py</a></p><p>And the Assessment model explicitly indexes it for querying later:</p><pre><code>prompt_version = Column(String, nullable=False, index=True)</code></pre><p>Full source: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/models/assessment.py">backend/app/models/assessment.py</a></p><p>So months later you can answer:</p><ul><li><p>&#8220;Which prompt version produced this coaching output?&#8221;</p></li><li><p>&#8220;Did v3 increase scores artificially vs v2?&#8221;</p></li><li><p>&#8220;When we changed the rubric, what shifted?&#8221;</p></li></ul><p>This is what it means to treat prompts like contracts: <strong>you can&#8217;t audit what you didn&#8217;t record.</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_WFm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_WFm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 424w, https://substackcdn.com/image/fetch/$s_!_WFm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 848w, https://substackcdn.com/image/fetch/$s_!_WFm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 1272w, https://substackcdn.com/image/fetch/$s_!_WFm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_WFm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png" width="1456" height="2643" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2643,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:676468,&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://blog.ademartutor.com/i/185061365?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.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_!_WFm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 424w, https://substackcdn.com/image/fetch/$s_!_WFm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 848w, https://substackcdn.com/image/fetch/$s_!_WFm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 1272w, https://substackcdn.com/image/fetch/$s_!_WFm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F54bbd6f4-12d0-4cfe-b0cd-b80179a2be35_3009x5462.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>How this enables &#8220;safe prompt iteration&#8221; without drift chaos</h2><p>Once your prompt is a contract, you can run a clean workflow:</p><ol><li><p><strong>Draft v3</strong> &#8212; You tweak the rubric to catch a new failure mode. No stress, it&#8217;s not live yet.</p></li><li><p><strong>Preview it</strong> &#8212; Hit the preview endpoint. See exactly what output the new prompt produces. No guessing.</p></li><li><p><strong>Evaluate offline</strong> &#8212; Run it against your gold set. Compare v3 vs v2 side-by-side. Did scores improve, or did you just move the goalposts?</p></li><li><p><strong>Promote it</strong> &#8212; One API call. The new contract is live. The old one is still in the database if you need to roll back.</p></li><li><p><strong>Observe with confidence</strong> &#8212; Every assessment is stamped. When your PM asks &#8220;what changed?&#8221; You <em>know</em>. When a customer disputes a score, you can show them exactly which rubric produced it.</p></li></ol><p>This is the difference between &#8220;I think we improved the model&#8221; and &#8220;I can prove v3 outperforms v2 on our gold set, and here&#8217;s the audit trail.&#8221;</p><h3>What does this actually save you?</h3><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{array}{|l|l|}\n\\hline\n\\textbf{Without prompt contracts} &amp; \\textbf{With prompt contracts} \\\\\n\\hline\n\\text{Debug metric shifts: 2-4 hours of git archaeology} &amp;\n\\text{Query by }\\texttt{prompt_version}\\text{: 30 seconds} \\\\\n\\hline\n\\text{Audit prep: &#8220;Let me find that old prompt&#8230;&#8221; (days)} &amp;\n\\text{Query the database by specific prompt ID} \\\\\n\\hline\n\\text{Rollback after bad deploy: redeploy + pray} &amp;\n\\text{Re-activate previous version by activating old prompt version} \\\\\n\\hline\n\\text{Multi-tenant customization: fork the codebase} &amp;\n\\text{Activate different prompt per org} \\\\\n\\hline\n\\end{array}\n\n&quot;,&quot;id&quot;:&quot;WCTINRTKQV&quot;}" data-component-name="LatexBlockToDOM"></div><p></p><p>For a team running 1,000+ evaluations/month, this pattern will pay for itself the first time the team needs to answer &#8220;why did tenant X&#8217;s scores change?&#8221;. A question that will take half a day and now takes one SQL query.</p><h2>The takeaway</h2><p>If you&#8217;re using LLM-as-a-Judge, your prompt isn&#8217;t &#8220;just a prompt.&#8221;</p><p>It&#8217;s the scoring contract. It defines what &#8220;good&#8221; means.</p><p>So treat it like production configuration:</p><ul><li><p>store it in the DB</p></li><li><p>version it</p></li><li><p>activate it per tenant</p></li><li><p>stamp every assessment with its version (and eventually its ID)</p></li><li><p>evaluate changes before you ship them</p></li></ul><p>That&#8217;s how you keep evaluation from drifting and keep your improvements real.</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[LLM-as-a-Judge Offline Evaluation for Ordinal Scores]]></title><description><![CDATA[Pearson r + QWK + &#177;1]]></description><link>https://blog.ademartutor.com/p/llm-as-a-judge-offline-evaluation</link><guid isPermaLink="false">https://blog.ademartutor.com/p/llm-as-a-judge-offline-evaluation</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Sat, 17 Jan 2026 01:45:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!aekP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For a long time, sailors could figure out latitude (north&#8211;south) by looking at the Sun and stars, but longitude (east&#8211;west) was a different story. Longitude required knowing the time difference between the local time on the ship (based on the Sun&#8217;s position) and the time at a fixed reference location (Greenwich).</p><p>The bottleneck at that time was clocks. The best clocks of the era were pendulum clocks. These clocks were great on land, terrible on a moving ship.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aekP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aekP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg 424w, https://substackcdn.com/image/fetch/$s_!aekP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg 848w, https://substackcdn.com/image/fetch/$s_!aekP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!aekP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aekP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg" width="600" height="516" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:516,&quot;width&quot;:600,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Clock Parts&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Clock Parts" title="Clock Parts" srcset="https://substackcdn.com/image/fetch/$s_!aekP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg 424w, https://substackcdn.com/image/fetch/$s_!aekP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg 848w, https://substackcdn.com/image/fetch/$s_!aekP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!aekP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe5dcd61e-a5bb-4cbc-b126-031f8d96c96f_600x516.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">Source: <a href="http://www.movinggraphics.ca/Clocks/Hour_Parts.html">http://www.movinggraphics.ca/Clocks/Hour_Parts.html</a></figcaption></figure></div><p>When the ship is being tossed around by the waves, the pendulum&#8217;s motion gets corrupted. And when your clock is wrong, you don&#8217;t just get the time wrong, you can end up navigating to the wrong place.</p><p>In 1735, everything changed when John Harrison built the first practical marine chronometer: a clock that kept accurate time <em>at sea</em>. Mechanically, the key shift was moving from pendulum regulation to <strong>balance + spring regulation</strong> (the same core concept behind mechanical watches).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bmA-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bmA-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bmA-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bmA-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bmA-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bmA-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg" width="1280" height="853" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:853,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:192035,&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;:false,&quot;internalRedirect&quot;:&quot;https://blog.ademartutor.com/i/184776905?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.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_!bmA-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 424w, https://substackcdn.com/image/fetch/$s_!bmA-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 848w, https://substackcdn.com/image/fetch/$s_!bmA-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!bmA-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7efed715-82d7-4f26-9183-d31ae63e834d_1280x853.jpeg 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">By User:Ktr101 - Ladd Observatory, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=45968685</figcaption></figure></div><p>The story seems familiar in the context of AI today.</p><p>A lot of LLM systems behave like pendulum clocks: impressive in calm conditions, unreliable when the environment shifts. Small changes in phrasing, missing context, messy inputs, or edge-case scenarios can swing outputs from spot-on to wildly off.</p><p>If we want AI apps that people can trust, we need the equivalent of Harrison&#8217;s chronometer: a mechanism that works <em>at sea</em>, not just in the lab.</p><p>The chronometer wasn&#8217;t a nicer map; it was a repeatable standard. In AI, <strong>evals</strong> are that standard: a way to measure reliability across rough conditions, not just demo conditions.</p><p>Evaluations turn model behavior into something we can measure, compare, and improve. Instead of trusting a prompt because it &#8220;sounds good,&#8221; we run it against a fixed <strong>gold set</strong>, quantify performance, and track whether changes actually make the system more consistent.</p><p>In other words: <strong>evals make reliability an engineering loop.</strong></p><p>Below, I&#8217;ll show how I built that loop for an <strong>LLM-as-a-judge</strong> that produces <strong>ordinal coaching scores </strong>for the sales coach app I&#8217;ve built (<a href="https://github.com/iamademar/llm-as-a-judge-sales-coach">https://github.com/iamademar/llm-as-a-judge-sales-coach</a>), and why I evaluate it with <strong>Pearson r + Quadratic Weighted Kappa + &#177;1 accuracy</strong>.</p><h2>The production scenario</h2><p>The concrete scenario here is a sales coaching app I built recently. </p><p>It takes a sales call transcript and produces two outputs:</p><ol><li><p><strong>Coaching feedback</strong> for the conversation (what went well, what to improve, suggested next moves)</p></li><li><p><strong>Ordinal 1&#8211;5 scores</strong> for each SPIN dimension (Situation, Problem, Implication, Need-Payoff)</p></li></ol><p>Under the hood, that assessment is produced by a prompt-based <strong>LLM judge</strong>: we pass the transcript plus a structured rubric/template, and the model returns scores + rationale. Here&#8217;s the demo of how it works in production:</p><div id="youtube2-R-5Q6pXu3oY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;R-5Q6pXu3oY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/R-5Q6pXu3oY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p></p><p>This kind of workflow shows up everywhere beyond sales coaching too, any time you&#8217;re using an LLM to <strong>grade</strong>, <strong>rank</strong>, <strong>extract</strong>, or <strong>decide</strong>: routing tickets, scoring leads, auditing calls, classifying documents, prioritizing follow-ups.</p><p>And in all of those cases, the real product isn&#8217;t &#8220;LLM output.&#8221;</p><p>The product is <strong>consistent decisions</strong>.</p><h2>The reliability problem</h2><p>Prompt-based judging is powerful, but it&#8217;s also easy to <em>believe your own demo</em>.</p><p>A prompt can look great on a few handpicked examples and still drift badly when:</p><ul><li><p>the transcript style changes,</p></li><li><p>the call gets messy,</p></li><li><p>the scenario is ambiguous,</p></li><li><p>the customer isn&#8217;t cooperative,</p></li><li><p>or the rep switches strategy mid-call.</p></li></ul><p>This is where many LLM features die in production: not because the model is &#8220;bad,&#8221; but because reliability becomes unpredictable. When the output affects something important like coaching, performance reviews, or decision-making&#8230; </p><p><strong>Unpredictable = Unshippable</strong></p><p>So the real question isn&#8217;t &#8220;does the prompt work?&#8221;</p><p>It&#8217;s:</p><blockquote><p><strong>Does this prompt produce consistent, calibrated scores that match how a human coach would rate the same conversation?</strong></p></blockquote><p>And if the market shifts (new playbook, new ICP, new sales motion), can we <strong>recalibrate</strong> without guessing?</p><p>Because the implication of getting this wrong isn&#8217;t just a &#8220;wrong score.&#8221; It&#8217;s downstream damage:</p><ul><li><p>managers stop trusting the tool and revert to manual reviews,</p></li><li><p>reps feel unfairly graded,</p></li><li><p>enablement focuses on the wrong behaviors,</p></li><li><p>and a promising AI feature is rolled back</p></li></ul><h2>The calibration loop</h2><p>The fix is to treat the judge like an instrument that needs calibration.</p><p>We build a small <strong>gold set</strong>: a curated set of transcripts that clearly fit the SPIN framework, each labeled with &#8220;gold standard&#8221; SPIN scores (and ideally short notes explaining why).</p><p>Then we run the evaluator prompt over that same dataset and compare:</p><ul><li><p>model scores vs. gold scores (per SPIN dimension)</p></li><li><p>aggregate performance across the dataset</p></li><li><p>failure cases (where it disagrees and why)</p></li></ul><p>If the metrics show the model is close enough and the failure cases are understandable, we treat the prompt as calibrated.</p><p>From there, every prompt change is tested the same way. That gives you two production-grade properties:</p><ol><li><p><strong>Confidence to ship:</strong> you can say &#8220;this version is better&#8221; with evidence</p></li><li><p><strong>Regression detection:</strong> you catch degradations before users do</p></li></ol><p>At this point, reliability becomes a repeatable loop.</p><p>Now we can talk about how to measure it correctly because the judge outputs <strong>1&#8211;5 coaching scores</strong>, and those labels are <strong>ordinal</strong>: they&#8217;re ordered, and how far off you are matters.</p><h2>Why &#8220;accuracy&#8221; is misleading for 1&#8211;5 coaching scores</h2><p>Exact-match accuracy treats these as equally wrong:</p><ul><li><p>Gold = 5, Pred = 4 &#9989; (close enough for coaching)</p></li><li><p>Gold = 5, Pred = 1 &#10060; (way off)</p></li></ul><p>Both are simply &#8220;wrong&#8221; under accuracy.</p><p>But in rubric scoring, distance matters. That&#8217;s exactly the use case for <strong>weighted kappa</strong> (where disagreements are penalized based on severity), and why QWK shows up in ordinal scoring benchmarks like automated essay scoring.</p><p>So instead of one brittle metric, I intentionally use three complementary &#8220;views&#8221; of quality&#8230;</p><p></p><h2>Why I use three metrics (not one)</h2><p>Prompt-based scoring isn&#8217;t something you &#8220;get right&#8221; once. It&#8217;s something you <strong>calibrate</strong>, then keep calibrated.</p><p>And because these scores are <strong>ordinal</strong> (1&#8211;5), you want metrics that answer three different production questions:</p><ol><li><p><strong>Are we moving in the right direction when the gold label moves?</strong> (trend alignment)</p></li><li><p><strong>Do we agree like a second rater would?</strong> (ordinal agreement)</p></li><li><p><strong>Are we close enough that the coaching experience still feels right?</strong> (product tolerance)</p></li></ol><p>That&#8217;s why I use:</p><ul><li><p><strong>Pearson r</strong> &#8594; checks trend alignment</p></li><li><p><strong>Quadratic Weighted Kappa (QWK)</strong> &#8594; checks ordinal agreement and punishes big misses</p></li><li><p><strong>&#177;1 accuracy</strong> &#8594; checks &#8220;close enough&#8221; from a coaching / UX standpoint</p></li></ul><p>Together, they give you a reliability signal that&#8217;s much harder to game than plain accuracy.</p><p></p><h2>Metric 1: Pearson r (trend alignment)</h2><p>In <code>backend/app/services/evaluation_metrics.py</code>, <code>pearson_r(...)</code> implements Pearson correlation with two practical &#8220;production-friendly&#8221; choices:</p><ul><li><p>If there&#8217;s only one data point, return <code>0.0</code></p></li><li><p>If either series has zero variance (constant predictions or constant gold labels), return <code>0.0</code></p></li></ul><pre><code><code># Handle single element case
if n == 1:
    return 0.0

# Handle zero variance case (constant array)
if var_true == 0.0 or var_pred == 0.0:
    return 0.0</code></code></pre><p>Source code: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/services/evaluation_metrics.py">https://github.com/iamademar/llm-as-a-judge-sales-coach/blob/main/backend/app/services/evaluation_metrics.py</a></p><p></p><h3>Why this is useful in production</h3><p>This prevents eval runs from exploding on edge cases <em>and</em> makes failure modes obvious.</p><p>If your judge collapses into &#8220;everything is a 3,&#8221; Pearson r doesn&#8217;t politely pretend you&#8217;re doing fine &#8212; it drops toward 0.</p><h3>What Pearson r catches</h3><ul><li><p><strong>&#8220;When gold goes up, predictions go up too.&#8221;</strong></p></li><li><p>Broad trend / rank alignment across transcripts</p></li></ul><h3>What Pearson r can miss</h3><ul><li><p><strong>Calibration drift:</strong> you can be consistently off by +1 or &#8722;1 and still get decent correlation</p></li></ul><p><strong>Translation:</strong> Pearson r tells you if the judge has the <em>right shape</em> &#8212; not whether it&#8217;s <em>well calibrated</em>.</p><p></p><h2>Metric 2: Quadratic Weighted Kappa (ordinal agreement)</h2><p>In the same file, <code>quadratic_weighted_kappa(...)</code> treats the LLM judge like a <strong>second rater</strong>.</p><p>Two details matter here.</p><h3>1) Quadratic penalty by distance</h3><p>The weight matrix is explicitly quadratic:</p><pre><code><code>weight_mat[i][j] = ((i - j) ** 2) / ((n_labels - 1) ** 2)
</code></code></pre><p>So:</p><ul><li><p>off by 1 &#8594; small penalty</p></li><li><p>off by 2+ &#8594; much larger penalty</p></li></ul><p>That matches how humans interpret rubric scores: a &#8220;4 vs 5&#8221; disagreement is a rounding error; &#8220;1 vs 5&#8221; is a broken judge.</p><h3>2) Sensible handling of degenerate cases</h3><p>If there&#8217;s no variation in labels (<code>n_labels == 1</code>), the function returns <code>1.0</code>:</p><pre><code><code>if n_labels == 1:
    return 1.0
</code></code></pre><p>This avoids the annoying situation where your eval run fails just because a small slice of data happens to be uniform.</p><h3>What QWK catches</h3><ul><li><p><strong>&#8220;We agree like raters would.&#8221;</strong></p></li><li><p>Big misses are heavily penalized &#8212; exactly what you want for coaching credibility</p></li></ul><h3>What QWK helps prevent (this is the production killer)</h3><ul><li><p>A judge that&#8217;s &#8220;directionally okay&#8221; but still frequently off by 2&#8211;4 points</p></li><li><p>The kind of disagreement that makes reps say: <em>&#8220;This is random.&#8221;</em></p></li></ul><p><strong>Translation:</strong> QWK tells you whether the judge is <em>trustworthy as a rater</em>, not just correlated.</p><p></p><h2>Metric 3: &#177;1 accuracy (coaching tolerance)</h2><p>The repo&#8217;s <code>plus_minus_one_accuracy(...)</code> is a pragmatic product metric:</p><pre><code><code>n_correct = sum(
    1 for yt, yp in zip(y_true, y_pred)
    if abs(yt - yp) &lt;= 1
)
return n_correct / len(y_true)
</code></code></pre><p>This answers the question your users actually feel:</p><p><strong>How often is the score close enough that the coaching still makes sense?</strong></p><h3>Why it matters</h3><p>In coaching workflows, &#8220;4 vs 5&#8221; usually yields similar guidance. Even if the exact number differs, the <em>actionable feedback</em> is often basically the same.</p><p>So &#177;1 accuracy is the metric that maps closest to perceived reliability.</p><h3>What &#177;1 accuracy catches</h3><ul><li><p><strong>&#8220;Close enough&#8221; performance</strong> that preserves a good UX</p></li><li><p>Whether prompt changes are making the judge <em>more usable</em></p></li></ul><h3>What it helps prevent</h3><ul><li><p>Quiet drift that technically looks &#8220;fine&#8221; on correlation but feels worse to users</p></li><li><p>The slow slide into <em>&#8220;this tool is kind of flaky&#8221;</em></p></li></ul><p><strong>Translation:</strong> &#177;1 is your <em>product guardrail</em> metric.</p><p></p><h2>How to interpret the three together</h2><p>Here&#8217;s the simplest way I&#8217;ve found to read these in practice:</p><ul><li><p><strong>Pearson r high, QWK low</strong> &#8594; good direction, poor agreement (calibration/labeling mismatch)</p></li><li><p><strong>QWK high, &#177;1 low</strong> &#8594; rare but catastrophic misses are happening (bad failure modes)</p></li><li><p><strong>&#177;1 high, QWK mediocre</strong> &#8594; UX feels okay, but big misses exist (risk of trust collapse)</p></li><li><p><strong>All three improving together</strong> &#8594; your judge is getting reliably better, not just &#8220;better on paper&#8221;</p></li></ul><p>That&#8217;s the real point of mixing metrics: you&#8217;re not optimizing a number, you&#8217;re making a judge that stays reliable when transcripts get messy and the world changes.</p><p></p><h2>Bringing it back to the chronometer</h2><p>Harrison didn&#8217;t make the ocean calmer. He built an instrument that stayed accurate anyway and navigators trusted it because it held up under real conditions.</p><p>Offline evaluation is our chronometer: the mechanism that keeps an LLM judge reliable.</p><p>And when the sales team shifts direction in response to the market, you don&#8217;t throw the system away. You update the <strong>gold set</strong> to reflect the new playbook and real examples, re-run the evals, and keep the judge aligned.</p><p>You don&#8217;t control the sea.<br>You recalibrate the instrument so it still tells the truth when things get rough.</p><p></p>]]></content:encoded></item><item><title><![CDATA[LLM-as-a-Judge for Sales Coaching]]></title><description><![CDATA[Designing an Auditable Evaluator Pipeline]]></description><link>https://blog.ademartutor.com/p/llm-as-a-judge-for-sales-coaching</link><guid isPermaLink="false">https://blog.ademartutor.com/p/llm-as-a-judge-for-sales-coaching</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Fri, 09 Jan 2026 16:09:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!P1lF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>LLM-as-a-Judge has matured!</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P1lF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P1lF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png 424w, https://substackcdn.com/image/fetch/$s_!P1lF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png 848w, https://substackcdn.com/image/fetch/$s_!P1lF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png 1272w, https://substackcdn.com/image/fetch/$s_!P1lF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P1lF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png" width="483" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/154b2ad5-7165-4172-8473-6a3bea967485_483x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:483,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot 2026-01-09 at 6.32.07&#8239;PM.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Screenshot 2026-01-09 at 6.32.07&#8239;PM.png" title="Screenshot 2026-01-09 at 6.32.07&#8239;PM.png" srcset="https://substackcdn.com/image/fetch/$s_!P1lF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png 424w, https://substackcdn.com/image/fetch/$s_!P1lF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png 848w, https://substackcdn.com/image/fetch/$s_!P1lF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.png 1272w, https://substackcdn.com/image/fetch/$s_!P1lF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154b2ad5-7165-4172-8473-6a3bea967485_483x600.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">Source: www.instagram.com/p/DNc38GHJoIy</figcaption></figure></div><p>We&#8217;re finally past the phase where <s>&#8220;LLMs can sort of grade things&#8221;</s>!</p><p>Today&#8217;s models are increasingly capable of acting as <strong>automated evaluators</strong>, and there&#8217;s now a growing body of research studying when (and how) LLM judgments align with human evaluation:</p><ul><li><p><strong>Zheng et al. (2023)</strong> &#8212; <a href="https://arxiv.org/abs/2306.05685">Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena</a></p></li><li><p><strong>Liu et al. (2023)</strong> &#8212; <a href="https://arxiv.org/abs/2303.16634">G-Eval: NLG Evaluation using GPT-4 with Better Human Alignment</a></p></li><li><p><strong>Kim et al. (2024)</strong> &#8212; <a href="https://arxiv.org/abs/2405.01535">Prometheus 2: An Open Source Language Model Specialized in Evaluating Other Language Models</a></p></li><li><p><strong>Chen et al. (2024)</strong> &#8212; <a href="https://aclanthology.org/2024.emnlp-main.474/">Humans or LLMs as the Judge? A Study on Judgement Bias</a></p></li><li><p><strong>Huang et al. (2025)</strong> &#8212; <a href="https://aclanthology.org/2025.findings-acl.306.pdf?utm_source=chatgpt.com">An Empirical Study of LLM-as-a-Judge for LLM Evaluation</a></p></li></ul><p>What better way to test this out than in <strong>sales coaching?</strong> Sales coaching is already a &#8220;judge&#8221; workflow.</p><p>Here&#8217;s a real-world scenario: <br><em>A sales coach listens to a call recording, then fills out a scorecard. They grade the rep across a playbook, let&#8217;s say SPIN (Situation, Problem, Implication, Need-Payoff) or your internal rubric, and add notes like:</em></p><ul><li><p><em>&#8220;They asked too many surface-level questions.&#8221;</em></p></li><li><p><em>&#8220;They didn&#8217;t push on impact.&#8221;</em></p></li><li><p><em>&#8220;Great discovery, but weak closing.&#8221;</em></p></li></ul><p>The problem is that judgment is <strong>expensive</strong>, <strong>time-consuming</strong>, and possibly <strong>inconsistent</strong>. Two coaches can score the same call differently. Depending on mood, the same coach might score it differently a week later. And when a sales rep challenges the score and asks a question like &#8220;Why did I get a 2 on Implication?&#8221;, the explanation is usually buried in messy notes.</p><p>That&#8217;s why sales coaching is a perfect proving ground for LLM-as-a-Judge: it forces you to treat evaluation as a <strong>system</strong>, not a one-off prompt.</p><p>If the model is going to &#8220;judge&#8221; a call, it needs to do what good coaches do:</p><ol><li><p>apply a consistent rubric,</p></li><li><p>produce structured scores, and</p></li><li><p>justify those scores with evidence from the call (transcript).</p></li></ol><p>If an AI coaching system that can&#8217;t explain <em>why</em> a score was given or reproduce that score the next week, it really isn&#8217;t an effective AI system.</p><p>In this post, I&#8217;ll walk through a production-grade <strong>LLM-as-a-Judge</strong> architecture for sales coaching. I&#8217;ll show how transcripts are evaluated, validated, stored, and continuously calibrated, using my open-source reference implementation: <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach/">https://github.com/iamademar/llm-as-a-judge-sales-coach/</a></p><div id="youtube2-DWmBqqWFgfQ" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;DWmBqqWFgfQ&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/DWmBqqWFgfQ?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p><em>Demo app deployed in <a href="https://frontend.icyforest-aa3b4633.southeastasia.azurecontainerapps.io/">Azure</a>.</em></p><h2>The Design: A Four-Stage Pipeline</h2><p>The assessment pipeline follows this sequence:</p><pre><code>Transcript &#8594; Judge &#8594; Validation &#8594; Persistence</code></pre><h3>Stage 1: Transcript Ingestion</h3><p>Every assessment starts with a raw conversation transcript. The frontend captures or uploads conversation data, which flows through our FastAPI backend:</p><pre><code># 1) Persist transcript first
transcript = Transcript(
    representative_id=req.metadata.get("representative_id"),
    buyer_id=req.metadata.get("buyer_id"),
    call_metadata=req.metadata,
    transcript=req.transcript,
)
db.add(transcript)
db.flush()  # Get ID before scoring</code></pre><p><strong>Why persist before scoring?</strong> This ensures that if the LLM call fails, the data is not lost. The transcript is the source of truth, and assessments are derived artifacts.</p><p></p><h3>Stage 2: The Judge</h3><p>The scoring service orchestrates the LLM evaluation. Here&#8217;s the complete flow from the scorer.py:</p><pre><code>def score_transcript(
    transcript: str,
    organization_id: Optional[uuid.UUID] = None,
    db: Optional[Session] = None,
) -&gt; tuple[dict, str, str]:
    """
    Score a sales transcript using SPIN framework via LLM.

    This is the main scoring pipeline that:
    1. Fetches organization's active prompt template from database
    2. Builds calibrated prompt (system + user) using the template
    3. Calls LLM to generate assessment
    4. Parses and validates JSON response
    5. Validates score ranges and required keys
    6. Returns assessment data with metadata

    Args:
        transcript: Sales conversation transcript with speaker tags (Rep:/Buyer:)
        organization_id: Organization UUID for fetching prompt template and LLM credentials
        db: Database session for template and credential lookup

    Returns:
        Tuple of (assessment_data, model_name, prompt_version) where:
        - assessment_data: dict with "scores" and "coaching" keys
        - model_name: LLM model identifier used
        - prompt_version: Prompt template version identifier

    Raises:
        ValueError: If transcript is empty, no active template found, or JSON parsing fails
        AssertionError: If scores are out of range [1, 5] or required keys missing

    Examples:
        &gt;&gt;&gt; os.environ["MOCK_LLM"] = "true"
        &gt;&gt;&gt; # Note: Requires organization with active template in test DB
        &gt;&gt;&gt; data, model, version = score_transcript("Rep: Hi\\nBuyer: Hello", org_id, db)
        &gt;&gt;&gt; "scores" in data and "coaching" in data
        True
    """
    # Step 1: Fetch organization's active prompt template
    if not organization_id or not db:
        raise ValueError("organization_id and db are required for scoring")

    template = template_crud.get_active_for_org(db, organization_id)
    if not template:
        raise ValueError(
            "No active prompt template found for organization. "
            "Please ensure a default template was created during setup."
        )

    # Step 2: Build calibrated prompt using org's template
    system, user = build_prompt(
        transcript,
        system_prompt=template.system_prompt,
        user_template=template.user_template,
    )
    prompt_version = template.version

    # Step 3: Call LLM (mock or real provider)
    raw_json = call_json(
        system,
        user,
        model=MODEL_NAME,
        temperature=0.0,
        response_format_json=True,
        organization_id=organization_id,
        db=db,
    )

    # Step 4: Parse JSON with guardrails
    data = parse_json_strict(raw_json)

    # Step 5: Validate required keys
    assert "scores" in data, "Missing required key 'scores' in LLM response"
    assert "coaching" in data, "Missing required key 'coaching' in LLM response"

    # Step 6: Validate score bounds (all must be 1-5)
    scores = data["scores"]
    required_score_keys = [
        "situation", "problem", "implication", "need_payoff",
        "flow", "tone", "engagement"
    ]

    for key in required_score_keys:
        assert key in scores, f"Missing required score key '{key}'"
        score_value = scores[key]
        assert isinstance(score_value, int), \
            f"Score '{key}' must be integer, got {type(score_value).__name__}"
        assert 1 &lt;= score_value &lt;= 5, \
            f"Score '{key}' must be in range [1, 5], got {score_value}"

    # Step 7: Validate coaching structure
    coaching = data["coaching"]
    required_coaching_keys = ["summary", "wins", "gaps", "next_actions"]

    for key in required_coaching_keys:
        assert key in coaching, f"Missing required coaching key '{key}'"

    # Return assessment with metadata for tracking
    return data, MODEL_NAME, prompt_version</code></pre><p><strong>Key design decision</strong>: The metadata alongside the assessment (model_name, prompt_version) is returned. This enables reproducibility and A/B testing of different prompt strategies.</p><p></p><h3>Stage 3: Validation with Guardrails</h3><p>LLMs rarely return clean JSON on first try. The guardrails handle the common failure modes:</p><pre><code>def parse_json_strict(raw: str) -&gt; dict:
    """
    Parse JSON with fallback strategies for LLM-generated content.

    Attempts multiple parsing strategies:
    1. Direct json.loads() on raw input
    2. Strip code fences (``` or ```json) and whitespace, then retry
    3. Raise ValueError with debugging context if all strategies fail

    Args:
        raw: Raw string that may contain JSON (possibly wrapped in code fences)

    Returns:
        Parsed JSON as a dictionary

    Raises:
        ValueError: If JSON cannot be parsed after all strategies, includes
                   first ~120 chars of input for debugging

    Examples:
        &gt;&gt;&gt; parse_json_strict('{"key": "value"}')
        {'key': 'value'}

        &gt;&gt;&gt; parse_json_strict('```json\\n{"key": "value"}\\n```')
        {'key': 'value'}

        &gt;&gt;&gt; parse_json_strict('```\\n{"key": "value"}\\n```')
        {'key': 'value'}
    """
    # Strategy 1: Try parsing as-is
    try:
        return json.loads(raw)
    except (json.JSONDecodeError, TypeError):
        pass

    # Strategy 2: Strip code fences and whitespace
    # Remove leading/trailing whitespace and newlines
    cleaned = raw.strip()

    # Pattern to match code fences with optional language specifier
    # Matches: ```json ... ``` or ``` ... ```
    fence_pattern = r'^```(?:json)?\s*\n?(.*?)\n?```$'
    match = re.match(fence_pattern, cleaned, re.DOTALL)

    if match:
        # Extract content between fences
        cleaned = match.group(1).strip()
    else:
        # Even without full fence pattern, strip any leading/trailing backticks
        cleaned = cleaned.strip('`').strip()

    # Try parsing cleaned version
    try:
        return json.loads(cleaned)
    except (json.JSONDecodeError, TypeError) as e:
        # Strategy 3: Raise with context
        preview = raw[:120] if len(raw) &gt; 120 else raw
        raise ValueError(
            f"Failed to parse JSON after cleanup strategies. "
            f"Error: {str(e)}. "
            f"Input preview (first 120 chars): {preview!r}"
        )
</code></pre><p>This parser handles:</p><ul><li><p><strong>Markdown wrapping</strong>: \``json {&#8230;} ````</p></li><li><p><strong>Extra whitespace</strong>: Leading/trailing newlines and spaces</p></li><li><p><strong>Debugging failures</strong>: Provides first 120 chars of raw output when all strategies fail</p></li></ul><p></p><h3>Stage 4: Persistence</h3><p>Once validated, the assessment is persisted with full metadata:</p><pre><code>class Assessment(Base):
    """
    SPIN framework assessment model.

    Stores LLM-generated scores and coaching feedback for a transcript.
    Tracks model name and prompt version for reproducibility and evaluation.
    """
    __tablename__ = "assessments"

    id = Column(Integer, primary_key=True, index=True, autoincrement=True)
    transcript_id = Column(
        Integer,
        ForeignKey("transcripts.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        comment="Reference to parent transcript"
    )
    scores = Column(
        JSON,
        nullable=False,
        comment="SPIN scores: {situation, problem, implication, need_payoff, flow, tone, engagement}"
    )
    coaching = Column(
        JSON,
        nullable=False,
        comment="Coaching feedback: {summary, wins, gaps, next_actions}"
    )
    model_name = Column(
        String,
        nullable=False,
        index=True,
        comment="LLM model identifier (e.g., 'gpt-4o-mini', 'claude-3-sonnet')"
    )
    prompt_version = Column(
        String,
        nullable=False,
        index=True,
        comment="Prompt template version (e.g., 'spin_v1', 'spin_v2')"
    )
    latency_ms = Column(
        Integer,
        nullable=True,
        comment="LLM call latency in milliseconds"
    )
    created_at = Column(
        DateTime(timezone=True),
        server_default=func.now(),
        nullable=False,
        comment="Timestamp when assessment was created"
    )

    # Relationship to transcript
    transcript_ref = relationship("Transcript", back_populates="assessments")

    def __repr__(self):
        return (
            f"&lt;Assessment(id={self.id}, transcript_id={self.transcript_id}, "
            f"model={self.model_name!r}, prompt_version={self.prompt_version!r})&gt;"
        )</code></pre><p><strong>Why store model_name and prompt_version?</strong> This enables:</p><ul><li><p>Compare different LLM providers (GPT-4 vs Claude vs Gemini)</p></li><li><p>Track prompt evolution and measure quality improvements</p></li><li><p>Debug regressions when scores drift</p></li><li><p>Run historical analyses on assessment quality</p></li></ul><p><em>Note: This can be seen on the demo where each assessment is labell with the LLM used.</em></p><p></p><h2>Reducing Drift with Rubrics and Schemas</h2><p>What keeps the system reliable is the explicit agreements between the LLM and our application about output format and scoring criteria. We&#8217;ve built both in prompt and through Pydantic validators.</p><h3>The Rubric: Calibrated Scoring Criteria</h3><p>Every LLM evaluation uses a detailed rubric that defines each score on a 1-5 scale. Here&#8217;s an excerpt from the default prompt template used on the app:</p><pre><code>SCORING RUBRIC (1-5 scale):

**situation** (1-5): Quality of situation questions
- 1: No situation questions; jumps to pitch
- 2: Minimal context gathering; superficial questions
- 3: Adequate situation questions covering basic context
- 4: Good situation questions establishing clear current state
- 5: Excellent situation questions; thorough understanding of buyer's environment

**problem** (1-5): Quality of problem questions
- 1: No problem identification; ignores pain points
- 2: Weak problem exploration; misses key issues
- 3: Identifies some problems but lacks depth
- 4: Good problem identification with clear pain points
- 5: Exceptional problem discovery; uncovers hidden issues

**implication** (1-5): Quality of implication questions
- 1: No exploration of consequences; stays surface-level
- 2: Minimal urgency building; weak consequence exploration
- 3: Some implication questions but lacks impact
- 4: Good implication development building urgency
- 5: Outstanding implication questions creating compelling urgency

**need_payoff** (1-5): Quality of need-payoff questions
- 1: No connection between solution and buyer value
- 2: Weak value proposition; generic benefits
- 3: Adequate need-payoff with some value connection
- 4: Strong need-payoff linking solution to specific pains
- 5: Exceptional need-payoff; buyer articulates own value

**flow** (1-5): Adherence to SPIN sequence (S&#8594;P&#8594;I&#8594;N)
- 1: Random questioning; no discernible structure
- 2: Poor flow; jumps between stages inconsistently
- 3: Follows SPIN loosely; some stage mixing
- 4: Good SPIN sequence with clear progression
- 5: Excellent SPIN flow; natural and purposeful transitions

**tone** (1-5): Professional, empathetic, confident, adaptive communication
- 1: Pitchy, monologue-style; ignores buyer cues
- 2: Inconsistent tone; occasional empathy gaps
- 3: Mixed empathy and clarity; adequate professionalism
- 4: Strong tone; professional, warm, and responsive
- 5: Exceptional tone; adaptive, empathetic, confident, concise

**engagement** (1-5): Active listening, reflection, buyer talk-time
- 1: Dominates conversation; no active listening
- 2: Limited listening; minimal buyer participation
- 3: Adequate engagement; balanced talk-time
- 4: Good engagement; actively listens and reflects
- 5: Outstanding engagement; buyer-led insights and high talk-time</code></pre><p><em>Note: This can be prompt can be tweaked so when the sales team learns better ways to approach sales conversations, the &#8220;judgement&#8221; can be recalibrated.</em></p><p>This rubric serves multiple purposes:</p><ol><li><p><strong>Anchors the LLM&#8217;s judgment</strong> to specific observable behaviors</p></li><li><p><strong>Reduces prompt sensitivity</strong> by explicitly defining what each score means</p></li><li><p><strong>Enables inter-rater reliability</strong> when comparing LLM vs human evaluations</p></li><li><p><strong>Documents the evaluation criteria</strong> for stakeholders and audits</p></li></ol><h3>The Schema: Enforcing Structure</h3><p>Alongside the rubric, we embed a <strong>JSON schema</strong> directly in the prompt:</p><pre><code>JSON SCHEMA (your response must match this exactly):
{{
  "type": "object",
  "properties": {{
    "scores": {{
      "type": "object",
      "properties": {{
        "situation": {{"type": "integer", "minimum": 1, "maximum": 5}},
        "problem": {{"type": "integer", "minimum": 1, "maximum": 5}},
        "implication": {{"type": "integer", "minimum": 1, "maximum": 5}},
        "need_payoff": {{"type": "integer", "minimum": 1, "maximum": 5}},
        "flow": {{"type": "integer", "minimum": 1, "maximum": 5}},
        "tone": {{"type": "integer", "minimum": 1, "maximum": 5}},
        "engagement": {{"type": "integer", "minimum": 1, "maximum": 5}}
      }},
      "required": ["situation", "problem", "implication", "need_payoff", "flow", "tone", "engagement"]
    }},
    "coaching": {{
      "type": "object",
      "properties": {{
        "summary": {{"type": "string"}},
        "wins": {{"type": "array", "items": {{"type": "string"}}}},
        "gaps": {{"type": "array", "items": {{"type": "string"}}}},
        "next_actions": {{"type": "array", "items": {{"type": "string"}}}}
      }},
      "required": ["summary", "wins", "gaps", "next_actions"]
    }}
  }},
  "required": ["scores", "coaching"]
}}</code></pre><p>We also reinforce this with Pydantic models on the application side:</p><pre><code>class AssessmentScores(BaseModel):
    """
    SPIN scoring model with additional conversation quality metrics.

    All scores must be integers in the range [1, 5] where:
    - 1 = Poor
    - 2 = Below Average
    - 3 = Average
    - 4 = Good
    - 5 = Excellent
    """
    situation: int = Field(..., ge=1, le=5, description="Quality of situation questions")
    problem: int = Field(..., ge=1, le=5, description="Quality of problem questions")
    implication: int = Field(..., ge=1, le=5, description="Quality of implication questions")
    need_payoff: int = Field(..., ge=1, le=5, description="Quality of need-payoff questions")
    flow: int = Field(..., ge=1, le=5, description="Overall conversation flow")
    tone: int = Field(..., ge=1, le=5, description="Tone and professionalism")
    engagement: int = Field(..., ge=1, le=5, description="Customer engagement level")

    @field_validator(
        "situation", "problem", "implication", "need_payoff",
        "flow", "tone", "engagement",
        mode="before"
    )
    @classmethod
    def validate_score_range(cls, v, info):
        """Ensure all scores are integers in valid range [1, 5]"""
        if not isinstance(v, int):
            raise ValueError(f"{info.field_name} must be an integer, got {type(v).__name__}")
        if v &lt; 1 or v &gt; 5:
            raise ValueError(f"{info.field_name} must be between 1 and 5, got {v}")
        return v</code></pre><p><strong>Why this dual approach?</strong></p><ul><li><p>The <strong>prompt-embedded schema</strong> guides the LLM&#8217;s output generation</p></li><li><p>The <strong>Pydantic validators</strong> catch any deviations before persistence</p></li><li><p>Together, they form a <strong>contract</strong> that dramatically reduces drift</p></li></ul><p></p><h2>Failure Modes: What We Learned the Hard Way</h2><p>Building this system revealed three major categories of failure. I&#8217;ve listed them below and the solution.</p><h3>1. Inconsistency: Score Drift Over Time</h3><p><strong>Problem</strong>: Early versions showed score inflation&#8212;the LLM would gradually shift toward higher scores without calibration.</p><p><strong>Solution</strong>:</p><ul><li><p>Explicit rubric anchoring (see above)</p></li><li><p>Temperature set to 0.0 for deterministic outputs</p></li><li><p>Tracking prompt_version to detect when drift correlates with prompt changes</p></li></ul><pre><code># Deterministic LLM calls
raw_json = call_json(
    system,
    user,
    model=MODEL_NAME,
    temperature=0.0,  # No randomness
    response_format_json=True,
    organization_id=organization_id,
    db=db,
)</code></pre><h3>2. Verbosity: When LLMs Over-Explain</h3><p><strong>Problem</strong>: LLMs would add commentary like &#8220;Here&#8217;s my assessment:&#8221; or wrap JSON in markdown, breaking parsers.</p><p><strong>Solution</strong>: Multi-strategy parsing with guardrails (see Stage 3 above) and explicit instructions:</p><pre><code># Immutable system prompt - instructs LLM behavior
SYSTEM = """You are a senior sales coach specializing in the SPIN (Situation, Problem, Implication, Need-Payoff) selling methodology.

Your task is to evaluate sales conversations and provide scoring and coaching feedback.

CRITICAL INSTRUCTIONS:
- Return STRICT JSON that exactly matches the provided JSON Schema
- Do NOT include any extra keys beyond those specified in the schema
- Do NOT wrap your response in markdown code blocks
- Ensure all scores are integers between 1 and 5 (inclusive)
- Base your assessment on evidence from the conversation transcript"""</code></pre><p>The system prompt is <strong>immutable</strong> and enforces strict JSON mode.<br></p><h3>3. Prompt Sensitivity: Small Changes, Big Impact</h3><p><strong>Problem</strong>: Tweaking prompt wording would cause score distributions to shift unexpectedly.</p><p><strong>Solution</strong>:</p><ul><li><p>Store prompts as <strong>versioned database records</strong> (not hardcoded strings)</p></li><li><p>Track prompt_version on every assessment</p></li><li><p>Run <strong>evaluation datasets</strong> before promoting new prompt versions</p></li></ul><pre><code>class PromptTemplate(Base):
    """
    Prompt template for SPIN assessments.

    Each organization has at least one template (v0 default created automatically).
    Only one template per organization can be active at a time.
    """

    __tablename__ = "prompt_templates"

    id = Column(
        UUID(),
        primary_key=True,
        default=uuid.uuid4,
        index=True,
        comment="Unique template identifier",
    )
    organization_id = Column(
        UUID(),
        ForeignKey("organizations.id", ondelete="CASCADE"),
        nullable=False,
        index=True,
        comment="Organization this template belongs to",
    )
    name = Column(
        String(100),
        nullable=False,
        comment="Human-readable template name",
    )
    version = Column(
        String(20),
        nullable=False,
        default="v0",
        comment="Version identifier (e.g., 'v0', 'v1', 'custom_v2')",
    )
    system_prompt = Column(
        Text,
        nullable=False,
        comment="System prompt defining LLM behavior",
    )
    user_template = Column(
        Text,
        nullable=False,
        comment="User prompt template (must contain {transcript} placeholder)",
    )
    is_active = Column(
        Boolean,
        default=False,
        server_default="false",
        nullable=False,
        comment="Only one template per org can be active",
    )
    created_at = Column(
        DateTime(timezone=True),
        server_default=func.now(),
        nullable=False,
        comment="Template creation timestamp",
    )
    updated_at = Column(
        DateTime(timezone=True),
        server_default=func.now(),
        onupdate=func.now(),
        nullable=False,
        comment="Template last update timestamp",
    )

    # Relationships
    organization = relationship("Organization", back_populates="prompt_templates")
    evaluation_runs = relationship(
        "EvaluationRun",
        back_populates="prompt_template",
        cascade="all, delete-orphan",
        order_by="desc(EvaluationRun.created_at)",
    )

    @property
    def latest_evaluation(self):
        """Get the most recent evaluation run for this template."""
        return self.evaluation_runs[0] if self.evaluation_runs else None
    
    @property
    def best_qwk_score(self):
        """Get the best QWK score across all evaluations."""
        if not self.evaluation_runs:
            return None
        valid_runs = [run.macro_qwk for run in self.evaluation_runs if run.macro_qwk is not None]
        return max(valid_runs) if valid_runs else None

    def __repr__(self):
        return (
            f"&lt;PromptTemplate(id={self.id}, "
            f"org={self.organization_id}, "
            f"name={self.name!r}, "
            f"version={self.version}, "
            f"is_active={self.is_active})&gt;"
        )</code></pre><p>This design enables <strong>A/B testing</strong> of prompt variants, provides the ability to roll back if a new prompt degrades quality, and allows for <strong>historical analysis</strong> of how prompts impact assessment quality.</p><p></p><h2>System Architecture</h2><p>If your looking at the code and need a map of how to read it, here&#8217;s the complete sequence diagram showing how a transcript flows through the system:</p><pre><code>&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; Frontend &#9474;
&#9474; (Next.js)&#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; POST /assess
     &#9474; { transcript, metadata }
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; FastAPI Router      &#9474;
&#9474; (assess.py)         &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; 1) Persist transcript
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; PostgreSQL          &#9474;
&#9474; transcripts table   &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; transcript_id
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; Scoring Service     &#9474;
&#9474; (scorer.py)         &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; 2) Fetch active prompt template
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; PostgreSQL          &#9474;
&#9474; prompt_templates    &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; system_prompt, user_template
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; Prompt Builder      &#9474;
&#9474; (build_prompt)      &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; 3) Build prompts with rubric + schema
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; LLM Client          &#9474;
&#9474; (llm_client.py)     &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; 4) Call OpenAI/Anthropic/Google
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; External LLM API    &#9474;
&#9474; (GPT-4, Claude, etc)&#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; raw JSON response
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; JSON Guardrails     &#9474;
&#9474; (parse_json_strict) &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; 5) Parse &amp; strip code fences
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; Schema Validator    &#9474;
&#9474; (scorer.py)         &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; 6) Validate scores [1-5], keys, types
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; PostgreSQL          &#9474;
&#9474; assessments table   &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; assessment_id, scores, coaching
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; FastAPI Response    &#9474;
&#9474; (AssessResponse)    &#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9516;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
     &#9474; 7) Return to frontend
     &#9660;
&#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
&#9474; Frontend &#9474;
&#9474; Dashboard&#9474;
&#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;</code></pre><h2>Key Takeaways</h2><p>If you&#8217;re building LLM-as-a-judge systems, these takeaways might be helpful:</p><ol><li><p><strong>Embed schemas in prompts</strong> &#8212; Don&#8217;t rely on post-hoc parsing alone</p></li><li><p><strong>Version your prompts</strong> &#8212; Treat them like code, store in DB with metadata</p></li><li><p><strong>Build guardrails at every layer</strong> &#8212; Prompt, parsing, application validation. Something like this:</p><pre><code># Layer 1: Prompt schema (in system prompt)

# Layer 2: Parsing guardrails
data = parse_json_strict(raw_json)

# Layer 3: Application validation
assert &#8220;scores&#8221; in data, &#8220;Missing required key &#8216;scores&#8217;&#8221;
for key in required_score_keys:
    assert key in scores, f&#8221;Missing score key &#8216;{key}&#8217;&#8221;
    assert 1 &lt;= scores[key] &lt;= 5, f&#8221;Score out of range: {scores[key]}&#8221;</code></pre><p><em>Note: For full details, see code on <a href="https://github.com/iamademar/llm-as-a-judge-sales-coach">github</a>.</em></p></li><li><p><strong>Track metadata religiously</strong> &#8212; model_name, prompt_version, latency_ms enable debugging. Really helpful later on! </p></li><li><p><strong>Evaluate before deploying</strong> &#8212; Use golden datasets with human labels for QA. In this scenario, these are conversations from sales reps that closed and considered a really good sales call.</p></li><li><p><strong>Set temperature to 0.0</strong> &#8212; Determinism reduces drift for structured outputs</p></li></ol><p>LLMs are powerful judges, but they need strong contracts and validation to become reliable production systems.</p><h2>Code References</h2><p>All code examples in this post are from the open-source codebase:</p><ul><li><p><strong>Scoring service</strong>: backend/app/services/scorer.py</p></li><li><p><strong>JSON guardrails</strong>: backend/app/utils/json_guardrails.py</p></li><li><p><strong>Assessment model</strong>: backend/app/models/assessment.py</p></li><li><p><strong>Assessment router</strong>: backend/app/routers/assess.py</p></li><li><p><strong>Prompt templates</strong>: backend/app/prompts/prompt_templates.py</p></li><li><p><strong>LLM client</strong>: backend/app/services/llm_client.py</p></li><li><p><strong>Prompt template model</strong>: backend/app/models/prompt_template.py</p></li><li><p><strong>Assessment schemas</strong>: backend/app/schemas/assessment.py</p></li></ul><p>The full source is available in the repository: <br><a href="https://ademartutor.substack.com/publish/post/184032760">https://github.com/iamademar/llm-as-a-judge-sales-coach</a></p><div><hr></div><p><strong>Questions or comments?</strong> I&#8217;d love to hear about your experiences building LLM judge systems. What failure modes have you encountered? What guardrails work best for your use case?</p>]]></content:encoded></item><item><title><![CDATA[Vibe Coding 2025: Context Engineering, DAGs, and the Shape of Modern Coding]]></title><description><![CDATA[A Coder&#8217;s Review of Cursor from Chat Prompts to Agentic Workflows]]></description><link>https://blog.ademartutor.com/p/vibe-coding-2025-context-engineering</link><guid isPermaLink="false">https://blog.ademartutor.com/p/vibe-coding-2025-context-engineering</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Sat, 27 Dec 2025 02:21:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!m95m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been using large language models to write code since ChatGPT first appeared in 2022. In the early days, it felt more like wrestling than collaborating. The models were impressive, but the suggestions were often outdated. Writing useful code meant spending almost as much time explaining context as solving the problem itself or checking if the suggested solution exists.</p><p>As the models improved, the friction didn&#8217;t disappear. It just changed shape. The challenge became managing tokens, deciding which files to reference, and constantly re-establishing state whenever tokens are almost out. The &#8220;intelligence&#8221; was there, but it added the responsibility of managing tokens. You had to manually select context, plan, validate, and correct errors every time.</p><p>When tools like Cursor first appeared, it felt like ChatGPT embedded inside an editor. It saved a few keystrokes and reduced context switching, but it didn&#8217;t immediately feel transformative. It was useful but still an incremental improvement.</p><p>That perception changed after using it across several real projects this year. Over time, Cursor stopped feeling like a chat tool and became something else entirely. The gains weren&#8217;t just coming from better prompts or smarter models. They stemmed from how the application itself had learned to work with LLMs.</p><p>It took a few real projects to see it clearly, but Cursor started removing friction in places I&#8217;d always assumed were just part of using LLMs.</p><h4><strong>Cursor does Automatic &#8220;context engineering&#8221; for you.</strong></h4><p>This is the biggest shift for me, and probably the easiest to miss if you haven&#8217;t felt the pain before, is context engineering.</p><p>With ChatGPT, <em>you</em> are the context engineer. You decide which files matter, copy snippets, summarise large modules, and hope you didn&#8217;t forget something important. When things go wrong, the model usually isn&#8217;t &#8220;wrong&#8221;. It&#8217;s responding to an incomplete or poorly structured context.</p><p>Cursor takes that responsibility.</p><p>Instead of asking you to supply context manually, it autonomously discovers, selects, and structures relevant code paths before the model ever reasons about your question.</p><p>In the screenshots below, I asked a deceptively simple question:</p><blockquote><p><em>&#8220;I want to change the evaluation from online to offline. What files do I need to change?&#8221;</em></p></blockquote><p>What happened next is the important part.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m95m!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m95m!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!m95m!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!m95m!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!m95m!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m95m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png" width="1456" height="901" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:901,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot 2025-12-26 at 6.01.16&#8239;PM.png&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="Screenshot 2025-12-26 at 6.01.16&#8239;PM.png" title="Screenshot 2025-12-26 at 6.01.16&#8239;PM.png" srcset="https://substackcdn.com/image/fetch/$s_!m95m!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!m95m!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!m95m!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!m95m!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28fcabb9-4c2f-408a-b891-dc541eee3d8b_3680x2276.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>Cursor didn&#8217;t ask for files or offer generic advice. It inspected the repository itself, traced the relevant evaluation paths, inferred what &#8220;offline&#8221; meant from the code, and returned a structured answer spanning backend, frontend, configuration, and 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_!IuGB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IuGB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!IuGB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!IuGB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!IuGB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IuGB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png" width="1456" height="901" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:901,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot 2025-12-26 at 6.01.44&#8239;PM.png&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="Screenshot 2025-12-26 at 6.01.44&#8239;PM.png" title="Screenshot 2025-12-26 at 6.01.44&#8239;PM.png" srcset="https://substackcdn.com/image/fetch/$s_!IuGB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!IuGB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!IuGB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!IuGB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1797a596-508e-4147-8353-a6f5f2ec4d79_3680x2276.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="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JkkX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JkkX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!JkkX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!JkkX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!JkkX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JkkX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png" width="1456" height="901" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:901,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot 2025-12-26 at 6.01.52&#8239;PM.png&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="Screenshot 2025-12-26 at 6.01.52&#8239;PM.png" title="Screenshot 2025-12-26 at 6.01.52&#8239;PM.png" srcset="https://substackcdn.com/image/fetch/$s_!JkkX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!JkkX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!JkkX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!JkkX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F76b073f2-c194-40ed-8aa2-e8b672c07629_3680x2276.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>Cursor uses the LLM throughout the process, including during code exploration. However, the exploration itself is constrained and scaffolded by deterministic tooling such as repository indexing, symbol graphs, and file search. The LLM helps reason about the code, but it isn&#8217;t responsible for discovering or assembling the context on its own.</p><h4><strong>Cursor orchestrates multiple LLM calls as DAGs</strong></h4><p>Another subtle shift is <em>how</em> Cursor uses large language models. It doesn&#8217;t rely on a single prompt that tries to do everything at once. Instead, it <strong>orchestrates multiple LLM calls</strong>, each with a narrowly defined role, and connects them into an execution graph that grows in complexity only when needed (like <a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG</a>).<br><br>When I asked:</p><blockquote><p>&#8220;I want to change the evaluation from online to offline. What files do I need to change?&#8221;</p></blockquote><p>You can see this happening in the screenshots.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yH1i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yH1i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png 424w, https://substackcdn.com/image/fetch/$s_!yH1i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png 848w, https://substackcdn.com/image/fetch/$s_!yH1i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png 1272w, https://substackcdn.com/image/fetch/$s_!yH1i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yH1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png" width="1436" height="1706" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1706,&quot;width&quot;:1436,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot 2025-12-26 at 9.47.37&#8239;PM.png&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="Screenshot 2025-12-26 at 9.47.37&#8239;PM.png" title="Screenshot 2025-12-26 at 9.47.37&#8239;PM.png" srcset="https://substackcdn.com/image/fetch/$s_!yH1i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png 424w, https://substackcdn.com/image/fetch/$s_!yH1i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png 848w, https://substackcdn.com/image/fetch/$s_!yH1i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.png 1272w, https://substackcdn.com/image/fetch/$s_!yH1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F07486525-fa22-4f2f-8d5d-f78acf150b49_1436x1706.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>Cursor explicitly reports multiple tool invocations during the process, progressively building up understanding before producing the explanation. That behavior is difficult to reproduce with a single-pass prompt, because the system needs to <em>decide what to look at next</em> based on what it has already learned.</p><h4><strong>Cursor provides application-specific UX for the human-in-the-loop.</strong></h4><p>Most LLM workflows still feel like &#8220;ask a question &#8594; get an answer.&#8221; Cursor turns it into a tighter cycle by giving you interactions that match how developers actually work. Instead of pushing everything through a chat window, it gives you features like <strong>inline edit</strong>, <strong>context-aware suggestions</strong>, and <strong>mode-driven flows</strong> that map nicely to an RPI workflow: <strong>Research &#8594; Planning &#8594; Implementation</strong>.</p><p>And this isn&#8217;t just useful on greenfield projects. It&#8217;s arguably <em>more</em> valuable when you&#8217;re stepping into an unfamiliar codebase. Imagine you&#8217;re new to a project and trying to understand how authentication works end-to-end. Instead of manually grepping for middleware, auth routes, token handling, and frontend state, you can start with a prompt like:</p><blockquote><p>&#8220;Show me how authentication works in this app. Start from the front-end until the back-end. Give a workflow diagram.&#8221;</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eGL1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eGL1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!eGL1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!eGL1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!eGL1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eGL1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png" width="1456" height="901" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:901,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot 2025-12-27 at 8.21.38&#8239;AM.png&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="Screenshot 2025-12-27 at 8.21.38&#8239;AM.png" title="Screenshot 2025-12-27 at 8.21.38&#8239;AM.png" srcset="https://substackcdn.com/image/fetch/$s_!eGL1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!eGL1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!eGL1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!eGL1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb5f95802-cfe8-40ef-8cfa-16d93d15e211_3680x2276.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>What I like about the result is that it doesn&#8217;t stay abstract. Cursor turns your question into a walkthrough: it identifies the real entry points (e.g., the login page and the /api/auth/login route), traces how requests are forwarded to the backend, and explains how tokens are stored and reused (access token vs refresh token, cookie handling, and the fetch helper that attaches auth).</p><p>The output becomes a navigable map you can verify immediately by jumping into the referenced files. So you&#8217;re not just reading an answer. You can actively validate your mental model of the system by adding logs or tweaking the code.</p><h3>4. Cursor has introduced agents... and this is where things get existential</h3><p>In mid-2025, agent-based workflows began to appear in mainstream dev tools. When <strong>OpenAI Codex</strong> was reintroduced, it showcased a new interaction model: you assign a task, a fleet of agents executes it, and you&#8217;re presented with a pull request to review. Cursor quickly followed with its own take on agent mode.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lYQB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lYQB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!lYQB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!lYQB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!lYQB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lYQB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png" width="1456" height="901" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:901,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Screenshot 2025-12-27 at 9.06.08&#8239;AM.png&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="Screenshot 2025-12-27 at 9.06.08&#8239;AM.png" title="Screenshot 2025-12-27 at 9.06.08&#8239;AM.png" srcset="https://substackcdn.com/image/fetch/$s_!lYQB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png 424w, https://substackcdn.com/image/fetch/$s_!lYQB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png 848w, https://substackcdn.com/image/fetch/$s_!lYQB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.png 1272w, https://substackcdn.com/image/fetch/$s_!lYQB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85d801cf-e133-412f-a70a-ec829a13fc6f_3680x2276.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>Up to this point, LLM tools, including Cursor were primarily collaborative. You stayed in the loop at every step: ask a question, review the answer, apply the change. Agents shift that boundary. Instead of collaborating <em>within</em> the task, you delegate the task and move into a reviewer role.</p><p>This looks like the &#8220;AGI endgame.&#8221; If a system can plan work, navigate a codebase, modify files, and submit a PR.</p><p>For me, it raises an uncomfortable question:</p><p>If AGI exists, why would we ask it to <em>build software for accounting professionals</em> instead of just <em>doing the accounting itself</em>?</p><p>This is where the idea of <strong>WaaS (Work as a Service)</strong> starts to feel more relevant than SaaS. The value shifts away from tools that <em>enable humans to work</em> toward systems that <em>perform the work directly</em>. Software stops being the product; execution does.</p><p>If that trend continues, it would shake up the outsourcing industry (BPO, software development, and managed services) as we know it.</p><p>I digress.</p><p>Agent mode today is still not reliable enough to fully cross that boundary. On real projects, agents can misunderstand intent, make locally &#8220;correct&#8221; changes that violate system-level assumptions, or drift once tasks span too many implicit constraints. The cost of review becomes really high because if the agent jumps into a rabbit hole, you know, you have to pick and choose the code. Unfortunately, it spent tokens already. And more tokens == more $$$.</p><p>This is true today. But will it be in the coming year?</p><p>Will agent workflows be genuinely reliable next year? Possibly. Will they redefine what &#8220;writing software&#8221; even means? Maybe. Either way, it&#8217;s one of the most interesting frontiers Cursor has opened up. </p><p>We will soon find out what happens in 2026.</p><p><em>See you then!</em></p>]]></content:encoded></item><item><title><![CDATA[Is Today a Good Day to Sell Coffee? ]]></title><description><![CDATA[A Beginner&#8217;s Guide to Decision Trees]]></description><link>https://blog.ademartutor.com/p/is-today-a-good-day-to-sell-coffee</link><guid isPermaLink="false">https://blog.ademartutor.com/p/is-today-a-good-day-to-sell-coffee</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Thu, 14 Aug 2025 04:25:14 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!v2DS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You&#8217;ve got a unique startup idea: a <strong>&#8220;Portable Coffee Shop&#8221; franchise</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!v2DS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!v2DS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 424w, https://substackcdn.com/image/fetch/$s_!v2DS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 848w, https://substackcdn.com/image/fetch/$s_!v2DS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!v2DS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!v2DS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg" width="1239" height="1102" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1102,&quot;width&quot;:1239,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!v2DS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 424w, https://substackcdn.com/image/fetch/$s_!v2DS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 848w, https://substackcdn.com/image/fetch/$s_!v2DS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!v2DS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F811d87cc-9124-4e4b-bfa8-3bdecf695919_1239x1102.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>What sets your franchise apart is its <strong>smart weather-based sales prediction system</strong>. Your unique value proposition? Franchisees can check whether today is an <em>optimal day (if you sell on this day, you're set for the month &#128514;) </em>to set up shop outdoors. If the forecast isn&#8217;t favorable, they can take the day off. No wasted effort!</p><p>Now it&#8217;s time for the next step:<br><strong>Build an app that predicts whether today is a good day to sell coffee outside.</strong></p><p><em>Example is simple enough, right? &#128514; After all, you&#8217;re not building the next ChatGPT, just trying to figure out if the weather says &#8220;sell&#8221; or &#8220;do not sell&#8221;</em></p><p>To get started, you look at historical data. After squinting at it long enough (and maybe one too many cups of coffee), you spot a pattern: when it&#8217;s <strong>sunny</strong> and the <strong>temperature is mild</strong>, it&#8217;s time to sell!</p><p>Here&#8217;s what your dataset looks like for the past five days:</p><pre><code>data = [ 
  {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "No"},
  {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "Yes"},
  {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "Yes"},
  {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "Yes"},
  {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "No"}
]</code></pre><p>If you&#8217;ve been developing apps for a long time like me, you&#8217;ll probably think of something like this immediately:</p><pre><code>def is_good_day_to_sell(outlook, temperature):
    if outlook == "Sunny":
        if temperature == "Hot":
            return "No"
        else:
            return "Yes"
    elif outlook == "Rainy":
        if temperature == "Cool":
            return "Yes"
        else:
            return "No"
    elif outlook == "Overcast":
        return "Yes"


# What you are trying to predict:
# {"Outlook": "Sunny", "Temperature": "Hot", "Sell": ???}
prediction = is_good_day_to_sell("Sunny", "Hot")
print("Prediction:", prediction)</code></pre><p>This function is_good_day_to_sell works! <strong>As long as the world never changes</strong>. It&#8217;s hardcoded based on the exact patterns you&#8217;ve seen so far. So if the input is familiar, it gives the correct answer.</p><p>But the moment a <strong>new combination</strong> shows up like this:</p><pre><code>{"Outlook": "Sunny", "Temperature": "Cool", "Sell": "???" }</code></pre><p>Should it return &#8220;Yes&#8221; or &#8220;No&#8221;?</p><p>Do you need to add more logical conditions? More &#8220;if&#8221;, &#8220;else&#8221;, or &#8220;loops&#8221;?</p><p>What you need is a function that can be trained to see new patterns and then predict. How do you do this?</p><p>To truly make your app smarter, you need to allow it to <strong>learn from data and adapt to new situations.</strong></p><p>You are now leaving the <strong>realm of rule-based deterministic programming</strong> to <strong>data-driven statistical learning (machine learning)</strong>.</p><p>Yes, it&#8217;s time for <strong>machine learning</strong>.</p><div><hr></div><p>You&#8217;ve done your research, and you&#8217;ve settled on creating a simple Decision Tree for the app.</p><p><em>P.S. This is a simplified example, not exactly ready to run your coffee empire&#8230; but we&#8217;ll get there &#9749;</em></p><p>What&#8217;s a <strong>decision tree</strong>?</p><p>A <strong>decision tree</strong> is like a flowchart that helps you make a decision step-by-step. At each step (called a &#8220;node&#8221;), the computer asks a <strong>yes/no</strong> or <strong>greater/less than</strong> question about a feature (or attribute) of the data.</p><p>At the end of the path (a &#8220;leaf&#8221;), the tree gives you a prediction, like a category or a value.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WrX_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WrX_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 424w, https://substackcdn.com/image/fetch/$s_!WrX_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 848w, https://substackcdn.com/image/fetch/$s_!WrX_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 1272w, https://substackcdn.com/image/fetch/$s_!WrX_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WrX_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png" width="992" height="551" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:551,&quot;width&quot;:992,&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_!WrX_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 424w, https://substackcdn.com/image/fetch/$s_!WrX_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 848w, https://substackcdn.com/image/fetch/$s_!WrX_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 1272w, https://substackcdn.com/image/fetch/$s_!WrX_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F640581a0-409a-45c3-b3a2-0c6270f23814_992x551.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When you look at the definition and image of a decision tree, you might wonder: <em>Couldn&#8217;t this just be done with a few logical conditions?</em></p><p>But this brings us back to a key idea, we need algorithms that can <strong>learn from data</strong> and <strong>adapt to new situations</strong>. A decision tree isn&#8217;t static; it must grow and be pruned dynamically based on the data.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oxf0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oxf0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 424w, https://substackcdn.com/image/fetch/$s_!oxf0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 848w, https://substackcdn.com/image/fetch/$s_!oxf0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 1272w, https://substackcdn.com/image/fetch/$s_!oxf0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oxf0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png" width="994" height="782" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:782,&quot;width&quot;:994,&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_!oxf0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 424w, https://substackcdn.com/image/fetch/$s_!oxf0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 848w, https://substackcdn.com/image/fetch/$s_!oxf0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 1272w, https://substackcdn.com/image/fetch/$s_!oxf0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F426e0dfd-795f-4351-a9c1-47c997cd0c61_994x782.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So, as I understand it, we are building a function that generates a function to predict for each new dataset.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ns02!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ns02!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ns02!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ns02!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ns02!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ns02!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg" width="410" height="668" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/caf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:668,&quot;width&quot;:410,&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_!ns02!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ns02!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ns02!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ns02!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaf8a934-f2ea-4a21-aa66-b7e73d9c978a_410x668.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">Codeception</figcaption></figure></div><p>So, the real question becomes: <em>How do we build such a tree from data?</em></p><p>To do that, there are two key mathematical concepts you need to understand: <strong>Entropy</strong> and <strong>Information Gain</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TDTV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TDTV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 424w, https://substackcdn.com/image/fetch/$s_!TDTV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 848w, https://substackcdn.com/image/fetch/$s_!TDTV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 1272w, https://substackcdn.com/image/fetch/$s_!TDTV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TDTV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png" width="158" height="158" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:158,&quot;width&quot;:158,&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_!TDTV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 424w, https://substackcdn.com/image/fetch/$s_!TDTV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 848w, https://substackcdn.com/image/fetch/$s_!TDTV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 1272w, https://substackcdn.com/image/fetch/$s_!TDTV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdfb1731f-98e8-4b53-a5d1-b6021d9d8a49_158x158.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>No worries, we&#8217;ll walk through them step by step. We won&#8217;t dive into the formal math proofs, but we <em>will</em> focus on how to translate the equations into code.</p><h3>Mathematical Concepts</h3><h3><strong>1. Entropy</strong></h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Q-B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Q-B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 424w, https://substackcdn.com/image/fetch/$s_!6Q-B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 848w, https://substackcdn.com/image/fetch/$s_!6Q-B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 1272w, https://substackcdn.com/image/fetch/$s_!6Q-B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Q-B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png" width="304" height="86" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:86,&quot;width&quot;:304,&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_!6Q-B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 424w, https://substackcdn.com/image/fetch/$s_!6Q-B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 848w, https://substackcdn.com/image/fetch/$s_!6Q-B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 1272w, https://substackcdn.com/image/fetch/$s_!6Q-B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3d9378d3-a6f3-450e-a176-e0bd1375e2fc_304x86.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>What is <strong>Entropy</strong>?<br>It&#8217;s the measure of how much impurity or uncertainty in a dataset.</p><ul><li><p>If all examples in a dataset belong to the same class, the entropy is 0 (pure).</p></li><li><p>If the examples are equally mixed (e.g., 50% &#8220;Yes&#8221;, 50% &#8220;No&#8221;), the entropy is maximum (e.g., in most examples I found, they are 1 or 0).</p></li></ul><p><em>Yep, the concept is too abstract.</em></p><p>So, let&#8217;s apply it to your dataset for some context:</p><pre><code>data = [ 
  {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "No"},
  {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "Yes"},
  {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "Yes"},
  {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "Yes"},
  {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "No"}
]</code></pre><p>Let&#8217;s calculate <strong>entropy</strong> for the target attribute <em>(What we want to predict)</em>: &#8220;Sell&#8221;</p><ul><li><p>Total examples: 5</p></li><li><p>&#8220;Yes&#8221;: 3</p></li><li><p>&#8220;No&#8221;: 2</p></li></ul><p>So:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7_NI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7_NI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 424w, https://substackcdn.com/image/fetch/$s_!7_NI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 848w, https://substackcdn.com/image/fetch/$s_!7_NI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 1272w, https://substackcdn.com/image/fetch/$s_!7_NI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7_NI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png" width="222" height="103" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:103,&quot;width&quot;:222,&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_!7_NI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 424w, https://substackcdn.com/image/fetch/$s_!7_NI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 848w, https://substackcdn.com/image/fetch/$s_!7_NI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 1272w, https://substackcdn.com/image/fetch/$s_!7_NI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf463577-5806-4f25-9b4b-6107cec9e9b7_222x103.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Substituting the values for the Entropy formula we get:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lSq_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lSq_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 424w, https://substackcdn.com/image/fetch/$s_!lSq_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 848w, https://substackcdn.com/image/fetch/$s_!lSq_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 1272w, https://substackcdn.com/image/fetch/$s_!lSq_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lSq_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png" width="475" height="32" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:32,&quot;width&quot;:475,&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_!lSq_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 424w, https://substackcdn.com/image/fetch/$s_!lSq_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 848w, https://substackcdn.com/image/fetch/$s_!lSq_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 1272w, https://substackcdn.com/image/fetch/$s_!lSq_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39025d7c-5965-401d-ad32-9859e9fc83eb_475x32.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>&#9989; Entropy = 0.971 bits (Entropy for target attribute &#8220;Sell&#8221;)</strong></p><p>You&#8217;ve learned the math, now you need to map it to code:</p><pre><code>from collections import Counter
import math

# --- Entropy Calculation Function ---
def entropy(data, target):
    # Count the occurrences of each class label in the target attribute
    # For example, in the "Sell" column, we count how many times 
    # "Yes" and "No" appear
    counts = Counter(row[target] for row in data)

    # Total number of examples in the dataset
    total = len(data)

    # Apply the entropy formula:
    # E(S) = -&#8721; (p_i * log2(p_i)) for each class i
    # Where p_i is the proportion of class i in the dataset
    return -sum((count / total) * math.log2(count / total) for count in counts.values())

# ------------------------------------
# &#129504; Let&#8217;s Apply It to Your Dataset
dataset = [
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "No"},
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "Yes"},
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "No"}
]

# We want to calculate the entropy of the target attribute: "Sell"
# Breakdown:
# Total examples = 5
# "Yes" = 3 &#8594; p_Yes = 3/5 = 0.6
# "No"  = 2 &#8594; p_No  = 2/5 = 0.4

# Entropy formula:
# E(S) = -[0.6 * log2(0.6) + 0.4 * log2(0.4)]
#      &#8776; -[0.6 * (-0.737) + 0.4 * (-1.322)]
#      &#8776; 0.971 bits

# &#9989; Now let's calculate it using our function:
result = entropy(dataset, "Sell")
print("Entropy of 'Sell':", round(result, 3))  # Expected output: 0.971</code></pre><div><hr></div><h3>2. Information Gain</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MhOh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MhOh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 424w, https://substackcdn.com/image/fetch/$s_!MhOh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 848w, https://substackcdn.com/image/fetch/$s_!MhOh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 1272w, https://substackcdn.com/image/fetch/$s_!MhOh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MhOh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png" width="538" height="90" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:90,&quot;width&quot;:538,&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_!MhOh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 424w, https://substackcdn.com/image/fetch/$s_!MhOh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 848w, https://substackcdn.com/image/fetch/$s_!MhOh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 1272w, https://substackcdn.com/image/fetch/$s_!MhOh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1220e766-424e-4754-b18b-9f0be052f3d9_538x90.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>Information Gain (IG)</strong> measures how much uncertainty (entropy) is reduced after splitting the data based on an attribute.</p><p>Again, let&#8217;s make this definition more understandable with examples on your data:</p><pre><code>dataset = [
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "No"},
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "Yes"},
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "No"}
]</code></pre><p>Let&#8217;s compute the information gain of the attribute: <strong>&#8220;Outlook&#8221;</strong></p><p>Step 1: Group by &#8220;Outlook&#8221;</p><pre><code>+----------+---------+-------------+
| Outlook  | Subset  | Sell values |
+----------+---------+-------------+
| Sunny    | Row 1,2 | No, Yes     |
| Rainy    | Row 3,5 | Yes, No     |
| Overcast | Row 4   | Yes         |
+----------+---------+-------------+</code></pre><p>Step 2: Compute the entropy of each subset</p><p>Outlook = Sunny (2 items)</p><ul><li><p>&#8220;No&#8221;: 1</p></li><li><p>&#8220;Yes&#8221;: 1</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OLmP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OLmP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 424w, https://substackcdn.com/image/fetch/$s_!OLmP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 848w, https://substackcdn.com/image/fetch/$s_!OLmP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 1272w, https://substackcdn.com/image/fetch/$s_!OLmP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OLmP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png" width="591" height="33" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:33,&quot;width&quot;:591,&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_!OLmP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 424w, https://substackcdn.com/image/fetch/$s_!OLmP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 848w, https://substackcdn.com/image/fetch/$s_!OLmP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 1272w, https://substackcdn.com/image/fetch/$s_!OLmP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F04705f00-cf2b-4271-87cf-950b49f4e81a_591x33.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Outlook = Rainy (2 items)</p><ul><li><p>&#8220;Yes&#8221;: 1</p></li><li><p>&#8220;No&#8221;: 1</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oR7i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oR7i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 424w, https://substackcdn.com/image/fetch/$s_!oR7i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 848w, https://substackcdn.com/image/fetch/$s_!oR7i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 1272w, https://substackcdn.com/image/fetch/$s_!oR7i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oR7i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png" width="583" height="33" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:33,&quot;width&quot;:583,&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_!oR7i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 424w, https://substackcdn.com/image/fetch/$s_!oR7i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 848w, https://substackcdn.com/image/fetch/$s_!oR7i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 1272w, https://substackcdn.com/image/fetch/$s_!oR7i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80e7dd7d-13c6-43e3-8e76-f47a21c75664_583x33.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Outlook = Overcast (1 item)</p><ul><li><p>&#8220;Yes&#8221;: 1</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PZZf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PZZf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 424w, https://substackcdn.com/image/fetch/$s_!PZZf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 848w, https://substackcdn.com/image/fetch/$s_!PZZf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 1272w, https://substackcdn.com/image/fetch/$s_!PZZf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PZZf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png" width="391" height="32" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:32,&quot;width&quot;:391,&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_!PZZf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 424w, https://substackcdn.com/image/fetch/$s_!PZZf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 848w, https://substackcdn.com/image/fetch/$s_!PZZf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 1272w, https://substackcdn.com/image/fetch/$s_!PZZf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29475434-6f9f-43db-9a5e-6f480b1116ae_391x32.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p><strong>&#9989; Information Gain for &#8220;Outlook&#8221; = 0.171</strong></p><p>You&#8217;ve learned the math, now you need to map it to code. Note that this uses the entropy function we&#8217;ve discussed above:</p><pre><code>def information_gain(data, feature, target):
    # Step 1&#65039;&#8419;: Compute the total entropy of the entire dataset using
    # only the target class
    # This corresponds to: E(S) = 0.971 in your example
    total_entropy = entropy(data, target)

    # Step 2&#65039;&#8419;: Get all unique values of the attribute 
    # we're evaluating (e.g., Outlook = Sunny, Rainy, Overcast)
    values = set(row[feature] for row in data)

    # Step 3&#65039;&#8419;: Initialize the weighted sum of entropies after the split
    weighted_entropy = 0.0

    # Step 4&#65039;&#8419;: For each value (e.g., "Sunny"), compute:
    for value in values:
        # a. Subset the dataset where feature == value 
        # (e.g., Outlook == Sunny)
        subset = [row for row in data if row[feature] == value]

        # b. Calculate the proportion of the subset relative 
        # to the total data
        weight = len(subset) / len(data)

        # c. Compute entropy of the subset (based only on 
        # the target variable "Sell")
        subset_entropy = entropy(subset, target)

        # d. Add this weighted entropy to the total
        weighted_entropy += weight * subset_entropy

    # Step 5&#65039;&#8419;: Subtract weighted entropy from total entropy to 
    # get Information Gain
    return total_entropy - weighted_entropy

    # &#129504; Let's Apply Information Gain to "Outlook"
    # Total entropy of "Sell" was calculated before: &#8776; 0.971

    # We'll now compute the weighted entropy after splitting by "Outlook":
    # Outlook has 3 unique values: Sunny, Rainy, Overcast

    # &#127780; Sunny subset:
    #   [{"Sunny", "Hot", "No"}, {"Sunny", "Mild", "Yes"}]
    #   - 2 samples: 1 Yes, 1 No &#8594; entropy = 1.0
    #   - weight = 2/5 = 0.4
    #   - weighted entropy = 0.4 &#215; 1.0 = 0.4

    # &#127783; Rainy subset:
    #   [{"Rainy", "Cool", "Yes"}, {"Rainy", "Mild", "No"}]
    #   - 2 samples: 1 Yes, 1 No &#8594; entropy = 1.0
    #   - weight = 2/5 = 0.4
    #   - weighted entropy = 0.4 &#215; 1.0 = 0.4

    # &#9729;&#65039; Overcast subset:
    #   [{"Overcast", "Hot", "Yes"}]
    #   - 1 sample: 1 Yes &#8594; entropy = 0
    #   - weight = 1/5 = 0.2
    #   - weighted entropy = 0.2 &#215; 0 = 0.0

    # &#128260; Total Weighted Entropy = 0.4 + 0.4 + 0.0 = 0.8

    # &#9989; Information Gain = Total Entropy - Weighted Entropy
    #                    = 0.971 - 0.8
    #                    = 0.171

    # Let's run the function:
    gain_outlook = information_gain(dataset, "Outlook", "Sell")
    print("Information Gain for 'Outlook':", round(gain_outlook, 3))  
    # Expected: 0.171</code></pre><p><em>In decision trees, it is used to select the best attribute to split on, the one that provides the highest IG. This will become clearer later once I use the information gain function.</em></p><div><hr></div><h3>Building the Tree</h3><p>We&#8217;ve built the functions for <strong>Entropy</strong> and <strong>Information Gain</strong>; the next step is to create a function that builds the tree.</p><p>Here&#8217;s the step on how we build the tree:</p><ol><li><p>Calculate <strong>Information Gain</strong> for &#8220;Outlook&#8221; and &#8220;Temperature&#8221;.</p></li><li><p>Select the feature with <strong>higher Information Gain</strong> (likely &#8220;Outlook&#8221;)</p></li><li><p>Split the data based on Outlook values (Sunny, Rainy, Overcast)</p></li><li><p>Recursively build subtrees for each branch.</p></li></ol><p>Here&#8217;s the code for that:</p><pre><code>def build_tree(data, features, target):
    
    # Extract all target labels from the current data subset
    # Example: if target="Sell", labels = ["No", "Yes", "Yes", "Yes", "No"]
    labels = [row[target] for row in data]
    
    # BASE CASE 1: Pure Node (All labels are the same)
    # If all instances have the same target label, create a leaf node
    # Example: labels = ["Yes", "Yes", "Yes"] &#8594; return "Yes"
    if labels.count(labels[0]) == len(labels):
        return labels[0]
    
    # BASE CASE 2: No Features Left (Feature exhaustion)
    # If we've used all features but still have mixed labels,
    # return the most common label (majority vote)
    # Example: labels = ["No", "Yes", "No"] &#8594; return "No" (majority)
    if not features:
        return Counter(labels).most_common(1)[0][0]

    # RECURSIVE CASE: Feature Selection and Splitting
    
    # Step 1: Calculate information gain for each remaining feature
    # Dictionary comprehension creates: {"Outlook": 0.25, "Temperature": 0.15}
    gains = {feature: information_gain(data, feature, target) for feature in features}
    
    # Step 2: Select the feature with the highest information gain
    # Uses max() with key=gains.get to find the key with maximum value
    best_feature = max(gains, key=gains.get)

    # Step 3: Create the tree node structure
    # Creates a dictionary where the key is the splitting feature
    # Example: {"Outlook": {}} - empty dict will hold the branches
    tree = {best_feature: {}}
    
    # Step 4: Get all unique values for the chosen feature
    # Example: if best_feature="Outlook", values = {"Sunny", "Rainy", "Overcast"}
    values = set(row[best_feature] for row in data)
    
    # Step 5: For each unique value, create a branch by recursive splitting
    for value in values:
        # Filter data to only include rows with this feature value
        # Example: subset for "Sunny" = all rows where Outlook="Sunny"
        subset = [row for row in data if row[best_feature] == value]
        
        # Recursively build a subtree for this subset using remaining features
        # Remove the current feature from available features to prevent reuse
        # Example: if we used "Outlook", remaining features = ["Temperature"]
        subtree = build_tree(subset, [f for f in features if f != best_feature], target)
        
        # Attach the returned subtree to the current tree node
        # Example: tree["Outlook"]["Sunny"] = {subtree for sunny conditions}
        tree[best_feature][value] = subtree

    # Return the completed tree structure
    # Final structure: 
    # Outlook?
    #   &#9500;&#9472;&#9472; Sunny:
    #   &#9474;   &#9492;&#9472;&#9472; Temperature?
    #   &#9474;       &#9500;&#9472;&#9472; Hot &#8594; Yes
    #   &#9474;       &#9492;&#9472;&#9472; Mild &#8594; No
    #   &#9500;&#9472;&#9472; Rainy:
    #   &#9474;   &#9492;&#9472;&#9472; Temperature?
    #   &#9474;       &#9500;&#9472;&#9472; Hot &#8594; Yes
    #   &#9474;       &#9492;&#9472;&#9472; Cool &#8594; No
    #   &#9492;&#9472;&#9472; Overcast:
    #       &#9492;&#9472;&#9472; Temperature?
    #           &#9500;&#9472;&#9472; Hot &#8594; No
    #           &#9492;&#9472;&#9472; Cool &#8594; Yes
    return tree</code></pre><div><hr></div><h3>Updating the function</h3><p>Based on what we&#8217;ve learned, now it&#8217;s time to update the <em>is_good_day_to_sell </em>function:</p><pre><code>def is_good_day_to_sell(tree, instance):
    """
    Prediction function that traverses a decision tree to make 
    predictions for new instances.Implements the inference/prediction 
    phase of the decision tree algorithm using recursion.
    
    Parameters:
    - tree: The trained decision tree structure (nested dictionaries) 
            created by build_tree
    - instance: A dictionary representing a new data point to classify 
                (e.g., {"Outlook": "Sunny", "Temperature": "Mild"})
    
    Returns:
    - The classification label (e.g., "Yes" or "No")
    
    Example traversal for instance {"Outlook": "Sunny", "Temperature": "Mild"}:
    Step 1: tree is dict, feature="Outlook", value="Sunny" 
    Step 2: subtree = tree["Outlook"]["Sunny"] (Temperature subtree)
    Step 3: Recursive call with Temperature subtree
    Step 4: tree is dict, feature="Temperature", value="Mild"
    Step 5: subtree = "Yes" (leaf node)
    Step 6: tree is not dict, return "Yes"
    """
    
    # BASE CASE - Leaf Node: If tree is not a dictionary, 
    # we've reached a leaf node containing the final 
    # prediction/classification label
    if not isinstance(tree, dict):
        return tree
    
    # Get the splitting feature from the current tree node
    # Since each tree node is a dictionary with one key (the splitting feature),
    # this extracts that feature name. Example: {"Outlook": {...}} &#8594; feature = "Outlook"
    feature = next(iter(tree))
    
    # Look up the value of the current feature in the instance being classified
    # Example: If feature="Outlook" and instance={"Outlook": "Sunny", ...}, then value="Sunny"
    value = instance.get(feature)
    
    # Navigate to the subtree corresponding to the instance's feature value
    # Example: tree["Outlook"].get("Sunny") returns the subtree for sunny conditions
    subtree = tree[feature].get(value)
    
    # RECURSIVE CASE: Continue traversing down the tree with the selected subtree
    # This follows the decision path through the tree based on the instance's feature values
    # until reaching a leaf node containing the final prediction
    return is_good_day_to_sell(subtree, instance)</code></pre><div><hr></div><h3>Evaluation</h3><p>This wouldn't feel like an AI blog if we didn&#8217;t compare our new algorithm to the previous one. How does our new algorithm compared to our original one?</p><p>Here&#8217;s how the evaluation was done:</p><pre><code>from build_tree import build_tree
from is_good_day_to_sell import is_good_day_to_sell
from static_tree_predict import static_tree_predict

# --- Dataset ---
dataset = [
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "No"},
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "Yes"},
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "No"}
]

features = ["Outlook", "Temperature"]
target = "Sell"

# Complex dataset
complex_dataset = [
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},     # contradiction to static
    {"Outlook": "Sunny", "Temperature": "Cool", "Sell": "No"},     # contradiction
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Hot", "Sell": "Yes"},     # unseen combo
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},     # contradiction
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "Yes"},    # flipped
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Overcast", "Temperature": "Cool", "Sell": "No"},  # exception
    {"Outlook": "Overcast", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},     # repeat for reinforcement
]

# Much more challenging dataset that exposes static tree limitations
challenging_dataset = [
    # Sunny days - Static tree says Hot=No, others=Yes
    # Let's make the pattern more complex: depends on both features together
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},      # Static: No, should be Yes
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},      # Reinforce pattern
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},      # Static gets this wrong
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "No"},      # Static: Yes, should be No
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "No"},      # Reinforce
    {"Outlook": "Sunny", "Temperature": "Cool", "Sell": "Yes"},     # Static: Yes, correct by luck
    {"Outlook": "Sunny", "Temperature": "Cool", "Sell": "Yes"},
    
    # Rainy days - Static tree says Cool=Yes, others=No  
    # Let's completely flip this pattern
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},      # Static: Yes, should be No
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},      # Reinforce
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},      # Static gets this wrong
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "Yes"},     # Static: No, should be Yes
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "Yes"},     # Reinforce
    {"Outlook": "Rainy", "Temperature": "Hot", "Sell": "Yes"},      # Static: No, should be Yes
    {"Outlook": "Rainy", "Temperature": "Hot", "Sell": "Yes"},      # Reinforce
    
    # Overcast days - Static tree always says Yes
    # Let's make it depend on temperature in a different way
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "No"},    # Static: Yes, should be No
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "No"},    # Reinforce
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "No"},    # Static gets this wrong
    {"Outlook": "Overcast", "Temperature": "Mild", "Sell": "Yes"},  # Static: Yes, correct by luck
    {"Outlook": "Overcast", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Overcast", "Temperature": "Cool", "Sell": "Yes"},  # Static: Yes, correct by luck
    {"Outlook": "Overcast", "Temperature": "Cool", "Sell": "Yes"},
    
    # Additional edge cases to really challenge the static tree
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},      # More evidence against static
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},      # More evidence against static
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "No"},    # More evidence against static
]

# Extreme challenge dataset - completely opposite to static tree assumptions
extreme_dataset = [
    # Make the static tree fail catastrophically
    # Sunny + Hot should be Yes (static says No)
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Sunny", "Temperature": "Hot", "Sell": "Yes"},
    
    # Sunny + others should be No (static says Yes)
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "No"},
    {"Outlook": "Sunny", "Temperature": "Mild", "Sell": "No"},
    {"Outlook": "Sunny", "Temperature": "Cool", "Sell": "No"},
    {"Outlook": "Sunny", "Temperature": "Cool", "Sell": "No"},
    
    # Rainy + Cool should be No (static says Yes)
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},
    {"Outlook": "Rainy", "Temperature": "Cool", "Sell": "No"},
    
    # Rainy + others should be Yes (static says No)
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Hot", "Sell": "Yes"},
    {"Outlook": "Rainy", "Temperature": "Hot", "Sell": "Yes"},
    
    # Overcast should sometimes be No (static always says Yes)
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "No"},
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "No"},
    {"Outlook": "Overcast", "Temperature": "Hot", "Sell": "No"},
    {"Outlook": "Overcast", "Temperature": "Mild", "Sell": "Yes"},
    {"Outlook": "Overcast", "Temperature": "Cool", "Sell": "Yes"},
]

def compare_predictions(tree, dataset, title=""):
    """Compare predictions between static tree and ML tree."""
    print(f"\n&#128202; {title}")
    print(f"{'Outlook':&lt;10} {'Temp':&lt;10} {'Actual':&lt;7} {'Static':&lt;8} {'ML Tree':&lt;8} {'Match?'}")
    for row in dataset:
        actual = row["Sell"]
        static_pred = static_tree_predict(row)
        ml_pred = is_good_day_to_sell(tree, row)
        match = "&#9989;" if static_pred == ml_pred else "&#10060;"
        print(f"{row['Outlook']:&lt;10} {row['Temperature']:&lt;10} {actual:&lt;7} {static_pred:&lt;8} {ml_pred:&lt;8} {match}")

def compute_accuracy(predict_fn, data, target):
    """Compute accuracy of a prediction function on a dataset."""
    correct = 0
    for row in data:
        if predict_fn(row) == row[target]:
            correct += 1
    return correct / len(data)

def detailed_comparison(tree, dataset, title=""):
    """Provide detailed analysis of where static vs ML tree differ"""
    print(f"\n&#128269; DETAILED ANALYSIS: {title}")
    print("="*80)
    
    static_correct = 0
    ml_correct = 0
    both_correct = 0
    both_wrong = 0
    static_better = 0
    ml_better = 0
    
    disagreements = []
    
    for row in dataset:
        actual = row["Sell"]
        static_pred = static_tree_predict(row)
        ml_pred = is_good_day_to_sell(tree, row)
        
        static_right = static_pred == actual
        ml_right = ml_pred == actual
        
        if static_right:
            static_correct += 1
        if ml_right:
            ml_correct += 1
            
        if static_right and ml_right:
            both_correct += 1
        elif not static_right and not ml_right:
            both_wrong += 1
        elif static_right and not ml_right:
            static_better += 1
        elif not static_right and ml_right:
            ml_better += 1
            
        if static_pred != ml_pred:
            disagreements.append({
                'case': f"{row['Outlook']}-{row['Temperature']}",
                'actual': actual,
                'static': static_pred,
                'ml': ml_pred,
                'static_right': static_right,
                'ml_right': ml_right
            })
    
    total = len(dataset)
    print(f"&#128200; ACCURACY COMPARISON:")
    print(f"   Static Tree:  {static_correct:2d}/{total} = {static_correct/total:.1%}")
    print(f"   ML Tree:      {ml_correct:2d}/{total} = {ml_correct/total:.1%}")
    print(f"   Improvement:  {ml_correct-static_correct:+2d} predictions = {(ml_correct-static_correct)/total:+.1%}")
    
    print(f"\n&#127919; AGREEMENT ANALYSIS:")
    print(f"   Both Correct: {both_correct:2d}/{total} = {both_correct/total:.1%}")
    print(f"   Both Wrong:   {both_wrong:2d}/{total} = {both_wrong/total:.1%}")
    print(f"   Static Better:{static_better:2d}/{total} = {static_better/total:.1%}")
    print(f"   ML Better:    {ml_better:2d}/{total} = {ml_better/total:.1%}")
    
    if disagreements:
        print(f"\n&#9876;&#65039;  DISAGREEMENTS ({len(disagreements)} cases):")
        print(f"{'Case':&lt;15} {'Actual':&lt;7} {'Static':&lt;7} {'ML':&lt;7} {'Winner'}")
        print("-" * 50)
        for d in disagreements:
            if d['static_right'] and not d['ml_right']:
                winner = "Static &#9989;"
            elif not d['static_right'] and d['ml_right']:
                winner = "ML &#9989;"
            elif not d['static_right'] and not d['ml_right']:
                winner = "Both &#10060;"
            else:
                winner = "Both &#9989;"
            print(f"{d['case']:&lt;15} {d['actual']:&lt;7} {d['static']:&lt;7} {d['ml']:&lt;7} {winner}")
    
    return {
        'static_accuracy': static_correct/total,
        'ml_accuracy': ml_correct/total,
        'improvement': (ml_correct-static_correct)/total,
        'disagreements': len(disagreements)
    }

if __name__ == "__main__":
    # Train the tree on original dataset
    tree = build_tree(dataset, features, target)
    print("&#127795; Learned Tree Structure:")
    print(tree)

    # Simple demo
    print("\n" + "="*50)
    print("&#128640; SIMPLE DEMO")
    print("="*50)
    test_instance = {"Outlook": "Sunny", "Temperature": "Mild"}
    print("Prediction for", test_instance, "-&gt;", is_good_day_to_sell(tree, test_instance))
    
    print("\n" + "="*100)
    print("&#129514; TESTING DIFFERENT DATASETS TO EXPOSE STATIC TREE LIMITATIONS")
    print("="*100)

    # Test 1: Original simple data
    print("\n" + "&#128313;"*50)
    print("TEST 1: Original Training Data (should work well for both)")
    detailed_comparison(tree, dataset, "Original Training Data")

    # Test 2: Basic complex data  
    print("\n" + "&#128313;"*50)
    print("TEST 2: Basic Complex Data (some contradictions)")
    detailed_comparison(tree, complex_dataset, "Basic Complex Data")

    # Test 3: More challenging data
    print("\n" + "&#128313;"*50)
    print("TEST 3: Challenging Dataset (systematic patterns opposite to static tree)")
    challenging_tree = build_tree(challenging_dataset, features, target)
    print(f"&#127795; New tree learned from challenging data: {challenging_tree}")
    detailed_comparison(challenging_tree, challenging_dataset, "Challenging Dataset")

    # Test 4: Extreme challenge
    print("\n" + "&#128313;"*50)
    print("TEST 4: Extreme Challenge (completely opposite patterns)")
    extreme_tree = build_tree(extreme_dataset, features, target)
    print(f"&#127795; New tree learned from extreme data: {extreme_tree}")
    detailed_comparison(extreme_tree, extreme_dataset, "Extreme Challenge Dataset")

</code></pre><p>This is the result:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;4f534262-c94c-4bc3-8a62-7c4589ed4dfe&quot;,&quot;duration&quot;:null}"></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xHaS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xHaS!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!xHaS!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!xHaS!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!xHaS!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xHaS!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&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_!xHaS!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!xHaS!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!xHaS!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!xHaS!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb89f9d1-18df-4b41-82b0-85df296db1d9_1920x1080.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">See the authentic surprise in my face after running it the nth time. &#128514;</figcaption></figure></div><p>This isn&#8217;t a very sophisticated evaluation, but it will hopefully give you an idea of why the Decision Tree learner is better than the static one. By the way, I&#8217;m calling the first version of the &#8220;prediction&#8221; function as <em>static_tree_predict</em> to distinguish it from the learning one, which is called the <em>is_good_day_to_sell</em>.</p><p><em>The reasoning on how the datasets is &#8220;harder&#8221; is commented on the code.</em></p><p>&#9989; <strong>Test 1: Original Training Data</strong></p><pre><code>+------------+-------------+---------------------------------+
| Metric     | Static Tree | ML Tree                         |
+------------+-------------+---------------------------------+
| Accuracy   | 100%        | 100%                            |
| Improvement| 0%          | &#8212;                               |
| Agreement  | Perfect     | Both agreed on every prediction |
+------------+-------------+---------------------------------+</code></pre><p><strong>&#129514; Test 2: Complex Dataset</strong></p><pre><code>+---------------+-------------+-------------------------+
| Metric        | Static Tree | ML Tree                 |
+---------------+-------------+-------------------------+
| Accuracy      | 30%         | 40%                     |
| Improvement   | +10%        | +1 correct prediction   |
| Disagreements | 1 case      | ML better in that case  |
+---------------+-------------+-------------------------+</code></pre><p>&#128293;<strong> Test 3: Challenging Dataset</strong></p><pre><code>+---------------+-------------+---------------------------+
| Metric        | Static Tree | ML Tree                   |
+---------------+-------------+---------------------------+
| Accuracy      | 30%         | 40%                       |
| Improvement   | +10%        | +1 correct prediction     |
| Disagreements | 1 case      | ML better in that case    |
+---------------+-------------+---------------------------+</code></pre><p>&#128680;<strong> Test 4: Extreme Challenge Dataset</strong></p><pre><code>+---------------+-------------+---------------------------+
| Metric        | Static Tree | ML Tree                   |
+---------------+-------------+---------------------------+
| Accuracy      | 9.1%        | 100%                      |
| Improvement   | +90.9%      | +20 correct predictions   |
| Disagreements | 20 cases    | All won by ML Tree        |
+---------------+-------------+---------------------------+</code></pre><h3>Observations</h3><p>The Decision Tree (ML tree), learns from data and adapts well to new patterns, showing significant improvement when the data distribution changes. However, it may fail when trained on flipped or misleading data and then tested on the original, revealing a risk of overfitting.</p><p>In contrast, the static tree (original code) relies on hardcoded logic and only performs well under fixed patterns. It fails catastrophically when exposed to unseen or contradictory inputs and cannot update itself without manual reprogramming, making it brittle in dynamic environments.</p><h3>Conclusion</h3><p>You&#8217;ve built the app ! Now it&#8217;s time to launch your startup and chase that unicorn status! &#129412; Go make it happen!</p><div><hr></div><h3>&#9749; Just a Quick Reality Check</h3><p>Okay, this whole post is a beginner-friendly crash course in Decision Trees. It&#8217;s meant to help you see how machines can learn from patterns, not replace scikit-learn, your favorite ML library, or actual data science best practices.</p><p>The code here is more of a proof of concept than something you&#8217;d ship to production. No error handling, no fancy pruning, no cross-validation. Just vibes, recursion, and decision-making magic. &#10024;</p><div><hr></div><p><em>Thanks for sticking with me this far! I know it got a bit lengthy. I couldn&#8217;t quite trim it down as much as I wanted. As a little reward, here&#8217;s a photo of my Dobermann pup, <strong>Claude</strong>, named after Claude Shannon, the father of information theory (yes, the same one behind Entropy and Information Gain).</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u5NL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u5NL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg 424w, https://substackcdn.com/image/fetch/$s_!u5NL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg 848w, https://substackcdn.com/image/fetch/$s_!u5NL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!u5NL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u5NL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg" width="1456" height="1941" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1941,&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_!u5NL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg 424w, https://substackcdn.com/image/fetch/$s_!u5NL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg 848w, https://substackcdn.com/image/fetch/$s_!u5NL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!u5NL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5baa763c-0f22-4b30-80ca-b24b27d093c3_1600x2133.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">Claude! &#128054;</figcaption></figure></div>]]></content:encoded></item><item><title><![CDATA[Design Thinking–Driven: From ML Ops to AI Engineering]]></title><description><![CDATA[How ML Teams can thrive in the Age of Plug-and-Play AI]]></description><link>https://blog.ademartutor.com/p/design-thinkingdriven-from-ml-ops</link><guid isPermaLink="false">https://blog.ademartutor.com/p/design-thinkingdriven-from-ml-ops</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Mon, 30 Jun 2025 09:59:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ohUk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ohUk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ohUk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ohUk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ohUk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ohUk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ohUk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg" width="523" height="850" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/de057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:850,&quot;width&quot;:523,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ohUk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ohUk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ohUk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ohUk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fde057614-8cd8-41ae-adeb-676c74be5041_523x850.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>&#128368; A Lesson from History</h2><p>The emergence of electricity in the late 19th and early 20th centuries forced many lamp-making companies into bankruptcy. But <strong>Edward Miller &amp; Co.</strong>, a prominent oil-lamp manufacturer based in Meriden, Connecticut, faced this pivotal moment differently. As electricity became more accessible, oil-lamp seems became more and more irrelevant. </p><p><strong>Edward Miller &amp; Co. </strong>didn&#8217;t resist the change. Instead they adapted. The company retrained its artisans, engineers, and factory workers to master electrical bulb design and production. The transition from handcrafted oil lamps to modern electric fixtures.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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>This wasn&#8217;t just a technological shift in their company. </p><p>It was an <strong>organizational transformation</strong>!</p><p></p><div><hr></div><p></p><h2>&#9889; The Foundation Model Shift</h2><p>The release of foundation models like GPT, Claude, and open-source versions started a pivotal shift in the AI landscape. </p><p>Initially, you needed elite research teams and millions to setup an infrastructure for AI. Now you can do the same thing via a simple API call.</p><p>AI became cheaper to implement!</p><p>Everyone wanted in. Many companies tried integrated AI into their products. </p><p>But beneath the surface, a surprising number still struggle to truly adapt. Ironically, even teams with established MLOps teams. How could these be?</p><blockquote><p>If your ML Ops team is one of those, don&#8217;t worry. You&#8217;re not alone. Even companies with top-tier data science talent are facing growing pains. But the ones who <em>act now</em> have a window of opportunity to leap ahead.</p></blockquote><h3><strong>&#129302; Why Traditional ML Ops Teams Struggle to Adapt?</strong></h3><p>Historically, ML Ops revolves around <strong>supervised learning</strong>. </p><p>What is supervised learning?</p><p>You collect labeled data, train a model, deploy it, monitor it, and retrain.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OCeE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OCeE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!OCeE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!OCeE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!OCeE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OCeE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png" width="1456" height="761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:761,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1074686,&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://blog.ademartutor.com/i/167149482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.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_!OCeE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!OCeE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!OCeE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!OCeE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3fec228f-104b-4ad7-9fb3-ce7892ba0c0a_3000x1567.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Examples of supervised learning are:</p><ul><li><p><strong>Fraud Detection:</strong> They train models on years of labeled transaction data to identify patterns indicative of fraudulent activity. Is this fraud or not?</p></li><li><p><strong>Product Recommendation:</strong> Teams use historical user behavior and purchase data to train models that suggest relevant products. Is this a relevant recommendation or not?</p></li><li><p><strong>Email Spam Detection:</strong> ML systems are trained on user-labeled emails to classify and filter out spam messages. Is this spam or not?</p></li></ul><p>But foundation models flip this script. They&#8217;re trained on huge and generalized data. They don&#8217;t need your labeled dataset to get started.</p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jRzY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jRzY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!jRzY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!jRzY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!jRzY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jRzY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png" width="1456" height="761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:761,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:948446,&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://blog.ademartutor.com/i/167149482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.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_!jRzY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!jRzY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!jRzY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!jRzY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d2f3228-f49c-4e6e-8256-d86c2e779a2b_3000x1567.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The challenge now with accessible foundation model is: <strong>how to prompt</strong>, <strong>fine-tune</strong>, or <strong>steer</strong> the model to deliver value. This demands a new mindset, one where your team needs to understand how to use models initially <strong>without direct training</strong> and <strong>with minimal data</strong></p><h2>&#127955; Ending the AI Ping-Pong</h2><p>Given how easy it is to start building AI feature, ML teams and product teams fall into this trap:</p><ul><li><p><strong>CEO</strong>: Let&#8217;s integrate AI!</p></li><li><p><strong>ML team</strong> ask product managers: &#8220;What do you want AI to do?&#8221;</p></li><li><p><strong>Product team</strong> ask ML engineers: &#8220;What can AI do?&#8221;</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_!1ez3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1ez3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png 424w, https://substackcdn.com/image/fetch/$s_!1ez3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png 848w, https://substackcdn.com/image/fetch/$s_!1ez3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png 1272w, https://substackcdn.com/image/fetch/$s_!1ez3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1ez3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png" width="1456" height="761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:761,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2972822,&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://blog.ademartutor.com/i/167149482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.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_!1ez3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png 424w, https://substackcdn.com/image/fetch/$s_!1ez3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png 848w, https://substackcdn.com/image/fetch/$s_!1ez3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.png 1272w, https://substackcdn.com/image/fetch/$s_!1ez3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F759d33e3-a0ea-4e07-ac71-78b737fd4422_3000x1568.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 loop goes nowhere. Without a shared workflow, nobody moves forward. This gap is exactly what <em>AI Engineering</em> aims to bridge. </p><blockquote><p>Start by solving something real. Then ask, &#8220;Can AI make this faster, easier, smarter, or more scalable?&#8221;</p></blockquote><p></p><h3><strong>&#129504; Rethinking ML Pipelines with AI Engineering</strong><em> </em>+<em> </em><strong>Design Thinking</strong></h3><div class="pullquote"><p>&#8220;The success of an ML system depends less on the fanciness of the model and more on how well the problem is defined and how well the solution is integrated into the product.&#8221;</p><p>Chip Huyen, <em>Designing Machine Learning Systems</em> (2022)</p></div><p>The way we integrate AI into products is shifting fundamentally. No longer do we start with a dataset and model. Instead, we begin with users: their pains, needs, and behavior. </p><h2>&#129302; <strong>AI Engineering (Design Thinking&#8211;Driven)</strong></h2><p>Inspired by Chip Huyen&#8217;s <em>AI Engineering</em> book,  I&#8217;ve adapted the workflow to start with <strong>customers</strong>, not the dataset. From my learnings of building and working with startups (many of which didn&#8217;t quite take off &#128517;), the rise of accessible foundation models should give us a chance to shift our focus from <strong>&#8220;What can AI do?&#8221;</strong> to &#8220;<strong>How can AI make our customers&#8217; lives easier?</strong>&#8221;</p><h4><strong>&#10060; Traditional ML Engineering:</strong></h4><blockquote><p><strong>Data &#10145; Model &#10145; Product &#10145; Customer</strong></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KV8b!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KV8b!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!KV8b!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!KV8b!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!KV8b!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KV8b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png" width="1456" height="761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:761,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:369499,&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://blog.ademartutor.com/i/167149482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.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_!KV8b!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!KV8b!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!KV8b!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!KV8b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff43f7a87-0a76-44c1-b774-d451b21177ca_3000x1567.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><ol><li><p><strong>Data:</strong> A team collects years of historical transaction records, each labeled as &#8220;fraud&#8221; or &#8220;not fraud.&#8221;</p></li><li><p><strong>Model:</strong> They train a supervised learning model to recognize patterns that indicate potential fraud.</p></li><li><p><strong>Product:</strong> The model is deployed into the company&#8217;s payment processing system to flag or block suspicious transactions in real-time.</p></li><li><p><strong>Customer:</strong> Customers benefit indirectly through enhanced security and fewer fraudulent charges on their accounts.</p></li></ol><p>It&#8217;s a proven system, but it assumes you already have <strong>structured data</strong> and a clear <strong>pattern to learn</strong>.</p><p></p><h4><strong>&#9989; AI Engineering (Design Thinking&#8211;Driven):</strong></h4><blockquote><p><strong>Customer &#10145; Product &#10145; Data &#10145; Model</strong></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!asHZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!asHZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!asHZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!asHZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!asHZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!asHZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png" width="1456" height="761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:761,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:371686,&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://blog.ademartutor.com/i/167149482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.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_!asHZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png 424w, https://substackcdn.com/image/fetch/$s_!asHZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png 848w, https://substackcdn.com/image/fetch/$s_!asHZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.png 1272w, https://substackcdn.com/image/fetch/$s_!asHZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9c1c149-c4cd-4e4f-b5fb-888e65de7712_3000x1567.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><ol><li><p><strong>Customer:</strong> A product team notices that users often struggle to write effective product descriptions. This is a real, high-friction user problem.</p></li><li><p><strong>Product:</strong> They respond by designing a &#8220;smart suggestion&#8221; feature directly within the editor to support users as they write.</p></li><li><p><strong>Data:</strong> As users begin interacting with this feature, the team collects anonymized drafts and completions to understand usage patterns and pain points.</p></li><li><p><strong>Model:</strong> With this data, they evaluate what foundation models can assist with (e.g., tone, clarity, SEO) and fine-tune or chain prompts to deliver helpful, personalized writing suggestions. If this is not enough, you can then later decide to<strong> augment the model with retrieval (RAG), integrate external tools (like grammar checkers or SEO analyzers), or design workflows with human-in-the-loop for higher quality control.</strong></p></li></ol><p>The process starts by solving a real user problem instead of building a model and looking for where to apply it. After identifying the problem, strategically bring in AI where it creates value.</p><blockquote><p>You can see companies like <strong>Notion</strong>, <strong>Canva</strong>, and <strong>Shopify</strong> are already embracing this approach. Embedding AI seamlessly into their products that it feels like a natural extension of the user experience. From Notion&#8217;s AI that enhances productivity without disrupting workflow, to Canva&#8217;s Magic Studio that empowers non-designers to create effortlessly, to Shopify&#8217;s Sidekick that supports merchants like a real teammate. These platforms prove that AI can be <strong>invisible in interface</strong>, <strong>intuitive in use</strong>, and <strong>deeply human in intent</strong>.</p></blockquote><h2><strong>&#127919; Takeaway</strong></h2><p>We&#8217;re early in this transformation. But like Edward Miller &amp; Co., the companies who adapt <em>now</em> will be the ones who lead.</p><ul><li><p>Don&#8217;t wait for ML teams to be told what to build.</p></li><li><p>Don&#8217;t wait for product teams to "get AI."</p></li><li><p>Start by solving something real.<strong> Then ask, &#8220;Can AI make this faster, easier, smarter, or more scalable?&#8221;</strong></p></li></ul><p>AI Engineering isn&#8217;t a rebrand. It&#8217;s a <strong>reorg</strong>anization. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e5FA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e5FA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg 424w, https://substackcdn.com/image/fetch/$s_!e5FA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg 848w, https://substackcdn.com/image/fetch/$s_!e5FA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!e5FA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e5FA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg" width="1456" height="1941" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1941,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2996948,&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://blog.ademartutor.com/i/167149482?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.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_!e5FA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg 424w, https://substackcdn.com/image/fetch/$s_!e5FA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg 848w, https://substackcdn.com/image/fetch/$s_!e5FA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!e5FA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb80b3654-85dc-44f2-a6c8-bfcf3b224ec7_2316x3088.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><blockquote><p>Here&#8217;s a photo of me trying to <em><strong>reorg</strong> </em>myself to learn what is possible<em> </em>with AI through the <a href="https://www.youtube.com/watch?v=XhiBw_qB5EM">Master of Artificial Intelligence program at the University of Waikato</a>, home of <a href="https://www.youtube.com/watch?v=TF1yh5PKaqI">Weka</a>.</p></blockquote><p></p><div><hr></div><p></p><h4>References</h4><p>Historic New England. (n.d.). <em>Electric lamp factory workers</em> [Photograph]. <a href="https://images.historicnewengland.org/rs/138533/scr/default.jpg">https://images.historicnewengland.org/rs/138533/scr/default.jpg</a></p><p>Huyen, C. (2024). <em>The AI engineering book</em>. Claypot AI. https://huyenchip.com/ai-engineering/book/</p><p>Bommasani, R., Hudson, D. A., Adeli, E., Altman, R., Arora, S., von Arx, S., ... &amp; Liang, P. (2021). <em>On the opportunities and risks of foundation models</em> (Stanford CRFM Report). <a href="https://crfm.stanford.edu/report.html">https://crfm.stanford.edu/report.html</a></p><p>Zhang, A., Lipton, Z. C., Li, M., &amp; Smola, A. J. (2021). <em>Dive into deep learning</em> (Version 1.0.0). https://d2l.ai</p><p>Anthropic. (2024). <em>How Notion uses Claude to help people work faster and smarter</em>. https://www.anthropic.com/customers/notion <a href="#user-content-fnref-1">&#8617;</a></p><p>Canva. (2023). <em>Canva launches Magic Studio, a suite of AI tools for everyday creators</em>. https://www.canva.com/newsroom/news/canva-ai-launches <a href="#user-content-fnref-2">&#8617;</a></p><p>Upskillist. (2024). <em>Hiring AI over humans? Decoding Shopify&#8217;s bold new strategy</em>. https://www.upskillist.com/blog/hiring-ai-over-humans-decoding-shopifys-bold-new-strategy <a href="#user-content-fnref-3">&#8617;</a></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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[Implementing PayPal Subscriptions in a SaaS App]]></title><description><![CDATA[PayPal subscriptions with Rails and Next.JS]]></description><link>https://blog.ademartutor.com/p/implementing-paypal-subscriptions</link><guid isPermaLink="false">https://blog.ademartutor.com/p/implementing-paypal-subscriptions</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Wed, 05 Mar 2025 04:02:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QQJF!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa056aef0-c970-416f-b6a2-e229161db3b1_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>Overview &#128214;</strong></h2><p><br>I dove into integrating PayPal subscriptions into a SaaS app using Rails on the backend and Next.js on the frontend. It took quite a bit of time, so I decided to document the process, tough decisions, tackling some tricky technical challenges, and building a smooth subscription workflow that really works.</p><p></p><h2><strong>Background &#127760;</strong></h2><p><br>The challenge? I was building a subscription payment system for a <a href="https://www.referslide.com/">SaaS startup</a> that was part of the <a href="https://ventures.aut.ac.nz/our-services/idea2impact-research-commercialisation-programme">2024 Cohort of AUT Venture&#8217;s IDEA2IMPACT program</a>. Initially, I was all set to use Stripe because of its awesome developer support and ease of use. But when I found out Stripe wasn&#8217;t available in our target country, I switched gears and went with PayPal instead.</p><p></p><h2><strong>Why PayPal &amp; The Initial Hurdles &#129300;</strong><br></h2><p><strong>Why PayPal?</strong></p><p>&#9989; A solid alternative when Stripe isn&#8217;t an option</p><p>&#128260; Supports recurring billing</p><p>&#128179; A well-established payment provider</p><p></p><p><strong>The Challenges I Faced:</strong></p><ul><li><p>Unlike Stripe, PayPal&#8217;s subscription API meant I had to make a bunch of manual API calls.</p></li><li><p>There&#8217;s no slick built-in UI for managing subscriptions.</p></li><li><p>And on top of that, PayPal webhooks were a bit hit or miss in production.</p><p></p></li></ul><h2><strong>Rolling Up My Sleeves with API Calls &#128295;</strong></h2><p><br>Since PayPal doesn&#8217;t offer an out-of-the-box UI for subscriptions, I had to set everything up manually using cURL requests. Here&#8217;s a quick rundown of the process to setup subscriptions in your terminal:</p><p><strong>Step 1: Generate an Access Token &#128273;</strong></p><pre><code>encoded_credentials=$(echo -n "CLIENT_ID:CLIENT_SECRET" | base64 -w 0)
curl -v -X POST "https://api-m.sandbox.paypal.com/v1/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Basic $encoded_credentials" \
-d "grant_type=client_credentials"</code></pre><p><strong>Step 2: Create a Product &#128717;&#65039;</strong></p><pre><code>curl -v -X POST "https://api-m.sandbox.paypal.com/v1/catalogs/products" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{
  "name": "My SaaS Product",
  "description": "SaaS subscription product",
  "type": "SERVICE",
  "category": "SOFTWARE",
  "home_url": "https://my-saas.com/"
}'
</code></pre><p><strong>Step 3: Create a Billing Plan &#128184;</strong></p><pre><code>curl -v -X POST "https://api-m.sandbox.paypal.com/v1/billing/plans" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-d '{
  "product_id": "PROD-12345",
  "name": "Starter Plan",
  "description": "Basic subscription plan",
  "status": "ACTIVE",
  "billing_cycles": [
    {
      "frequency": { "interval_unit": "MONTH", "interval_count": 1 },
      "tenure_type": "REGULAR",
      "sequence": 1,
      "total_cycles": 0,
      "pricing_scheme": { "fixed_price": { "value": "49.99", "currency_code": "USD" } }
    }
  ],
  "payment_preferences": { "auto_bill_outstanding": true, "payment_failure_threshold": 3 }
}'
</code></pre><h2>Bringing It All Together in Rails &amp; Next.js &#128260;</h2><p>Here&#8217;s how I built the subscription flow:</p><ul><li><p><strong>Frontend (Next.js):</strong> I rendered a PayPal button using the PayPal Button SDK. When a user clicked it and subscribed, PayPal returned a <code>subscriptionID</code>, which was then sent to my Rails backend.</p></li><li><p><strong>Backend (Rails):</strong> I saved the subscription details and set up scheduled jobs to periodically sync with PayPal for any updates.</p></li></ul><p><strong>Next.js Code for the PayPal Button &#128187;</strong></p><pre><code>const PaypalSubscriptionButton = ({ planId }) =&gt; {
  useEffect(() =&gt; {
    window.paypal.Buttons({
      createSubscription: (data, actions) =&gt; actions.subscription.create({ plan_id: planId }),
      onApprove: (data) =&gt; handleSubscriptionSuccess(data.subscriptionID),
    }).render("#paypal-button");
  }, []);

  const handleSubscriptionSuccess = async (subscriptionID) =&gt; {
    await fetch("/api/company_subscription", {
      method: "POST",
      body: JSON.stringify({ 
        subscription: { paypal_subscription_id: subscriptionID, plan_id: planId } 
      }),
    });
  };

  return &lt;div id="paypal-button"&gt;&lt;/div&gt;;
};</code></pre><p>Rails API Endpoint to Save the Subscription &#128221;</p><pre><code>class Api::CompanySubscriptionsController &lt; ApplicationController
  def create
    subscription_params = params.require(:subscription).permit(:paypal_subscription_id, :plan_id)
    subscription = Subscription.create!(subscription_params)
    render json: { subscription: subscription }, status: :created
  end
end
</code></pre><h2><strong>Keeping Track of Subscription Status &#9201;&#65039;</strong></h2><p>Because PayPal webhooks were a bit unreliable, I set up a scheduled job that periodically fetches subscription updates:</p><pre><code>class SyncPaypalSubscriptionDetailsJob &lt; ApplicationJob
  def perform(subscription_id)
    subscription = Subscription.find_by(id: subscription_id)
    return unless subscription
    return if subscription.paypal_subscription_id.blank?

    paypal_service = PaypalSubscriptionService.new
    subscription_details = paypal_service.get_subscription_details(subscription.paypal_subscription_id)

    subscription.update(
      status: subscription_details["status"].downcase,
      next_billing_date: Time.zone.parse(subscription_details.dig("billing_info", "next_billing_time"))
    )
  end
end
</code></pre><h2><strong>Final Takeaway &#127919;</strong></h2><p><br>This project was a deep dive into integrating PayPal subscriptions in a SaaS environment. While PayPal&#8217;s API required more hands-on work compared to Stripe, I managed to build a robust system by using scheduled polling to handle subscription updates. </p><p>Starting with a lean MVP and iterating as needed turned out to be a winning strategy.</p><p></p><p>References:</p><ul><li><p>Github repo: <a href="https://github.com/iamademar/nextjs-rails-paypal-demo">https://github.com/iamademar/nextjs-rails-paypal-demo</a></p></li></ul><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Optimizing Bank Marketing Campaigns with AI]]></title><description><![CDATA[Predicting Customer Subscription to a Term Deposit in a Portuguese Bank]]></description><link>https://blog.ademartutor.com/p/optimizing-bank-marketing-campaigns</link><guid isPermaLink="false">https://blog.ademartutor.com/p/optimizing-bank-marketing-campaigns</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Sun, 02 Feb 2025 07:14:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!QQJF!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa056aef0-c970-416f-b6a2-e229161db3b1_500x500.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Banks waste time and money calling uninterested customers in term deposit campaigns. What if AI could predict <strong>who's likely to subscribe</strong> before even dialing?</p><p>By analyzing past marketing data, we can build a <strong>machine learning model</strong> to:<br>&#9989; <strong>Cut marketing costs</strong> by focusing on high-potential leads.<br>&#9989; <strong>Boost efficiency</strong> by reducing unnecessary calls.<br>&#9989; <strong>Enhance customer experience</strong> by avoiding spam.<br>&#9989; <strong>Increase revenue</strong> through better conversions.</p><p>In this article, we&#8217;ll explore the dataset, train a predictive AI model, and see how banks can <strong>apply real-time insights to optimize campaigns</strong>. &#128640;</p><h2>&#127919; Business Impact: Why is this Useful?</h2><p>This model allows the bank to:</p><ol><li><p><strong>Reduce Marketing Costs</strong> &#8594; The bank can avoid calling uninterested customers.</p></li><li><p><strong>Improve Efficiency</strong> &#8594; Focus on high-potential leads, increasing campaign success rates.</p></li><li><p><strong>Enhance Customer Experience</strong> &#8594; Avoid spamming uninterested customers.</p></li><li><p><strong>Increase Revenue</strong> &#8594; More term deposit subscriptions lead to better bank profitability.</p></li></ol><div><hr></div><h2><strong>&#128204; Background: Why Train the Model?</strong></h2><p>The Portuguese banking institution has been running <strong>direct phone-based marketing campaigns</strong> to encourage customers to <strong>subscribe to term deposits</strong>. However, these campaigns involve <strong>multiple calls per customer</strong>, leading to high operational costs and wasted resources on uninterested clients.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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>To optimize these efforts, the bank wants to <strong>train a machine learning model</strong> that can predict which customers are <strong>most likely to subscribe to a term deposit</strong>. This prediction will allow the bank to:</p><ul><li><p>Focus marketing efforts on <strong>highly interested customers</strong>.</p></li><li><p>Reduce <strong>unnecessary phone calls</strong> and operational costs.</p></li><li><p>Improve <strong>conversion rates</strong> and overall campaign efficiency.</p></li></ul><p>The dataset contains <strong>detailed information about customers and their interactions with previous marketing campaigns</strong>, including <strong>demographics, past interactions, and loan history</strong>.</p><p>Dataset: <a href="https://archive.ics.uci.edu/dataset/222/bank+marketing">https://archive.ics.uci.edu/dataset/222/bank+marketing</a></p><div><hr></div><h2><strong>&#128202; Understanding the Dataset</strong></h2><p>The dataset consists of <strong>41,188 customer records</strong> with <strong>20 features</strong>, collected between <strong>May 2008 and November 2010</strong>. The target variable <strong>(</strong><code>y</code><strong>)</strong> is <strong>binary</strong>:</p><ul><li><p><strong>"yes"</strong> &#8594; The customer subscribed to a term deposit.</p></li><li><p><strong>"no"</strong> &#8594; The customer did not subscribe.</p></li></ul><h3><strong>&#128313; Key Features in the Dataset</strong></h3><ol><li><p><strong>Customer Demographics</strong></p><ul><li><p><code>age</code>: Age of the customer.</p></li><li><p><code>job</code>: Type of job (e.g., "admin", "blue-collar", "student").</p></li><li><p><code>marital</code>: Marital status (e.g., "married", "single").</p></li><li><p><code>education</code>: Level of education (e.g., "university degree", "high school").</p></li></ul></li><li><p><strong>Financial Information</strong></p><ul><li><p><code>balance</code>: Customer&#8217;s average yearly balance (in euros).</p></li><li><p><code>default</code>: Whether the customer has <strong>credit in default</strong>.</p></li><li><p><code>housing</code>: Whether the customer has a <strong>housing loan</strong>.</p></li><li><p><code>loan</code>: Whether the customer has a <strong>personal loan</strong>.</p></li></ul></li><li><p><strong>Marketing Campaign Interactions</strong></p><ul><li><p><code>contact</code>: Type of contact used (cellular vs. telephone).</p></li><li><p><code>day_of_week</code> &amp; <code>month</code>: When the customer was last contacted.</p></li><li><p><code>duration</code>: Last call duration (<strong>&#9888;&#65039; should be discarded for realistic predictions</strong> as it&#8217;s known after the call).</p></li><li><p><code>campaign</code>: Number of contacts in the current campaign.</p></li><li><p><code>pdays</code>: Days since the customer was last contacted (<strong>-1 means no prior contact</strong>).</p></li><li><p><code>previous</code>: Number of previous contacts.</p></li><li><p><code>poutcome</code>: Outcome of the previous campaign (e.g., "failure", "success").</p></li></ul></li></ol><div><hr></div><h2><strong>&#128736;&#65039; Code</strong></h2><h3><strong>Step 1: Load the Dataset</strong></h3><pre><code>import pandas as pd

# Load the dataset
df = pd.read_csv("bank-additional-full.csv", sep=";")  # Using semicolon as separator</code></pre><ul><li><p>The bank has recorded customer responses from past campaigns.</p></li><li><p>The dataset is loaded for preprocessing and analysis.</p></li></ul><h3><strong>Step 2: Data Preprocessing</strong></h3><p>Before training a model, we need to clean and transform the data.</p><pre><code>from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer

# Identify categorical and numerical features
categorical_features = ["job", "marital", "education", "contact", "month", "poutcome"]
numerical_features = ["age", "balance", "campaign", "pdays", "previous"]

# Drop 'duration' since it's not available before a call is made
df = df.drop(columns=["duration"])

# Encode categorical and numerical data
preprocessor = ColumnTransformer(
    transformers=[
        ("num", StandardScaler(), numerical_features),  # Scale numerical values
        ("cat", OneHotEncoder(), categorical_features)  # Convert categorical values
    ]
)

# Encode target variable
le = LabelEncoder()
df["y"] = le.fit_transform(df["y"])  # Convert 'yes'/'no' to 1/0

# Split into train and test sets
X = df.drop(columns=["y"])
y = df["y"]
X_train, X_test, y_train, y_test = train_test_split(preprocessor.fit_transform(X), y, test_size=0.2, random_state=42)</code></pre><p>Why do this?</p><ul><li><p><strong>StandardScaler</strong> ensures that numeric values are normalized.</p></li><li><p><strong>OneHotEncoder</strong> converts categorical values into <strong>machine-readable format</strong>.</p></li><li><p><strong>Drop &#8216;duration&#8217;</strong> because <strong>it is only available after the call</strong>.</p></li><li><p><strong>Train-test split</strong> ensures we test our model on unseen customers.</p></li></ul><h3><strong>Step 3: Train a Deep Learning Model</strong></h3><p>The bank wants to use a neural network to capture complex relationships between customer data and subscription likelihood.</p><pre><code>import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout

# Define a neural network model
model = Sequential([
    Dense(64, input_dim=X_train.shape[1], activation="relu"),
    Dropout(0.5),  # Prevents overfitting
    Dense(32, activation="relu"),
    Dropout(0.5),
    Dense(1, activation="sigmoid")  # Outputs probability (0 to 1)
])

# Compile the model
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])

# Train the model
history = model.fit(X_train, y_train, epochs=50, batch_size=32, validation_split=0.2, verbose=1)</code></pre><p>The deep learning model used in this script is a <strong>Multi-Layer Perceptron (MLP)</strong>, a type of Artificial Neural Network (ANN). It consists of fully connected (dense) layers and is designed for binary classification.</p><h4>&#128204; Why Use This Deep Learning Model for This Dataset?</h4><p>A Multi-Layer Perceptron (MLP) is used because:</p><ol><li><p>Handles Both Categorical &amp; Numerical Data</p></li></ol><ul><li><p>The dataset includes both categorical (e.g., job, marital status) and numerical (e.g., balance, age) features.</p></li><li><p>The preprocessing pipeline encodes categorical variables and normalizes numerical values, making it well-suited for an MLP.</p></li></ul><ol start="2"><li><p>Captures Complex Patterns</p></li></ol><ul><li><p>Bank marketing data has non-linear relationships between features.</p></li><li><p>MLP can detect interactions between variables (e.g., how age + job type + previous campaign success influences customer behavior).</p></li></ul><ol start="3"><li><p>Better Than Logistic Regression for Large Datasets</p></li></ol><ul><li><p>Logistic Regression works well for simple binary classification but struggles with high-dimensional data.</p></li><li><p>MLP can learn complex decision boundaries from features.</p></li></ul><ol start="4"><li><p>Dropout Layers Help Prevent Overfitting</p></li></ol><ul><li><p>Overfitting is a common issue in marketing datasets.</p></li><li><p>Dropout (0.5) ensures the model generalizes well to unseen data.</p></li></ul><h3><strong>Step 3: Train a Deep Learning Model</strong></h3><p>The bank wants to use a neural network to capture complex relationships between customer data and subscription likelihood.</p><pre><code>import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout

# Define a neural network model
model = Sequential([
    Dense(64, input_dim=X_train.shape[1], activation="relu"),
    Dropout(0.5),  # Prevents overfitting
    Dense(32, activation="relu"),
    Dropout(0.5),
    Dense(1, activation="sigmoid")  # Outputs probability (0 to 1)
])

# Compile the model
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])

# Train the model
history = model.fit(X_train, y_train, epochs=50, batch_size=32, validation_split=0.2, verbose=1)</code></pre><h3><strong>Step 4: Making Predictions on New Customers</strong></h3><p>The trained model can now be used to predict if new customers are likely to subscribe.</p><pre><code># Predict on test data
y_pred = model.predict(X_test)
y_pred = (y_pred &gt; 0.5).astype(int).flatten()  # Convert probability to binary class</code></pre><ul><li><p>If <code>y_pred = 1</code>, the customer is likely to subscribe.</p></li><li><p>If <code>y_pred = 0</code>, the customer is unlikely to subscribe.</p></li></ul><h3><strong>Step 5: Evaluating the Model&#8217;s Performance</strong></h3><p>How well does the model perform in predicting customer subscriptions?</p><pre><code>from sklearn.metrics import precision_score, recall_score, f1_score

# Evaluate model performance
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)

print(f"Precision: {precision:.3f}")
print(f"Recall: {recall:.3f}")
print(f"F1 Score: {f1:.3f}")</code></pre><p><strong>&#9989; Precision</strong> &#8594; How many of the predicted "yes" were actually correct?</p><p><strong>&#9989; Recall</strong> &#8594; How many actual "yes" were correctly identified?</p><p><strong>&#9989; F1 Score</strong> &#8594; A balance between Precision and Recall.</p><h3>&#128204; How can we integrated the model we developed?</h3><p>We can create a real-time prediction for Bank Marketing Campaigns. Here's how I imagine it would look like.</p><h4>&#127942; Scenario</h4><p>A <strong>surveyor</strong> is using a <strong>mobile application</strong> during a <strong>field campaign</strong> to gather customer information. &#128241;</p><ul><li><p><strong>&#128221; Data Collection</strong></p><ul><li><p>The surveyor inputs the following details into the app for a new customer, <strong>John</strong>:<br>&#9989; <strong>Age:</strong> 35<br>&#9989; <strong>Marital Status:</strong> Married<br>&#9989; <strong>Job:</strong> Blue-collar<br>&#9989; <strong>Housing Loan:</strong> No<br>&#9989; <strong>Personal Loan:</strong> No<br>&#9989; <strong>Contact Method:</strong> Cellular<br>&#9989; <strong>Outcome of Previous Campaign:</strong> Success</p></li></ul></li><li><p><strong>&#9889; Real-Time Prediction</strong></p><ul><li><p>&#128228; Upon submitting John's information, the app <strong>sends a request</strong> to the <strong>Django-based API</strong> hosting the <strong>predictive model</strong>.</p></li><li><p>&#128161; The API <strong>processes the data</strong> and returns a prediction:</p></li><li><p>&#128202; <strong>Probability of Subscription:</strong> <strong>78%</strong></p></li></ul></li><li><p><strong>&#127919; Actionable Insight</strong></p><ul><li><p>&#128276; The app displays a notification:</p></li><li><p><strong>"High likelihood of subscription. Prioritize follow-up with this customer."</strong></p></li><li><p>&#128172; The surveyor, <strong>armed with this insight</strong>, can tailor the conversation to <strong>increase the chances of conversion</strong>.</p></li></ul></li></ul><p>&#128640; With this AI-driven approach, marketing efforts become more efficient, improving success rates while reducing wasted resources!</p><p>P.S. </p><ul><li><p>You can run this code on <a href="https://colab.research.google.com/drive/15SOzhBogFUWrBAXZuUdhAG09KoaHlOY9?usp=sharing">Google Colab</a>.</p></li><li><p>Github repo <a href="https://github.com/iamademar/bank-marketing-campaign-with-ai/tree/main">here</a>.</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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[Class Scheduling with AI: Using Google OR-Tools for Constraint Satisfaction Problem ]]></title><description><![CDATA[Creating a Python script with Google OR-Tools to help solve class scheduling problem]]></description><link>https://blog.ademartutor.com/p/class-scheduling-with-ai-using-google</link><guid isPermaLink="false">https://blog.ademartutor.com/p/class-scheduling-with-ai-using-google</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Thu, 08 Aug 2024 09:22:51 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4e8a4370-b572-4086-82b0-5718ad6d4429_1120x630.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Is ChatGPT capable of scheduling classes for me? My brother posed this question, and my immediate response was, &#8220;Absolutely!&#8221; All we need to do is input the class schedule and specify our requirements, and it should generate a list of suitable classes.</p><p>So I tried prompting ChatGPT, and the initial version was something like this:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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_!PP42!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PP42!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png 424w, https://substackcdn.com/image/fetch/$s_!PP42!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png 848w, https://substackcdn.com/image/fetch/$s_!PP42!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png 1272w, https://substackcdn.com/image/fetch/$s_!PP42!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PP42!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png" width="478" height="270.60330578512395" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b04cf57f-514e-463f-8791-6181cb7c966f_968x548.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:548,&quot;width&quot;:968,&quot;resizeWidth&quot;:478,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PP42!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png 424w, https://substackcdn.com/image/fetch/$s_!PP42!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png 848w, https://substackcdn.com/image/fetch/$s_!PP42!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.png 1272w, https://substackcdn.com/image/fetch/$s_!PP42!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb04cf57f-514e-463f-8791-6181cb7c966f_968x548.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">This is how lazy I have become knowing that ChatGPT can understand wrong spellings because of contextual knowledge. LOL ;)</figcaption></figure></div><p>After a few tries of those basic prompts and not getting the result. I realized it wasn&#8217;t as straightforward as I initially thought. </p><p>Here&#8217;s how I navigated the process and ultimately succeeded:</p><h2><strong>Exploring Prompt Engineering with ChatGPT</strong></h2><p>I began using basic prompts, but they didn&#8217;t yield the desired results. This led me to experiment with <strong>Instruction-Following Prompting</strong>.</p><h3><strong>What is Instruction-Following Prompting?</strong></h3><p>In the context of large language models (LLMs), this technique involves giving clear, detailed instructions to guide the AI in producing the desired output while adhering to specific constraints.</p><p>In the context of AI and large language models (LLMs), this technique involves giving clear, detailed instructions to guide the AI in producing the desired output while adhering to specific constraints.</p><p>Here&#8217;s the approach I used:</p><p>1. <strong>Inputs:</strong> Provided two Excel files containing the class schedules.<br>2. <strong>Instructions:</strong> Included target courses, ensured minimum time between classes, etc.<br>3. <strong>Constraints:</strong> Specified time slots to avoid.<br>4. <strong>Desired Output:</strong> An Excel file with separate sheets for each schedule option.</p><p>Here&#8217;s how I applied the technique:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p-tQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p-tQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png 424w, https://substackcdn.com/image/fetch/$s_!p-tQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png 848w, https://substackcdn.com/image/fetch/$s_!p-tQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!p-tQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p-tQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png" width="318" height="436.1711899791232" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1314,&quot;width&quot;:958,&quot;resizeWidth&quot;:318,&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_!p-tQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png 424w, https://substackcdn.com/image/fetch/$s_!p-tQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png 848w, https://substackcdn.com/image/fetch/$s_!p-tQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!p-tQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad539271-542a-43da-b42d-5a770c39b2c9_958x1314.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>But for some reason, the prompt returned timeouts:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yXmQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yXmQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 424w, https://substackcdn.com/image/fetch/$s_!yXmQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 848w, https://substackcdn.com/image/fetch/$s_!yXmQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 1272w, https://substackcdn.com/image/fetch/$s_!yXmQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yXmQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png" width="534" height="77.99105812220566" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:196,&quot;width&quot;:1342,&quot;resizeWidth&quot;:534,&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_!yXmQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 424w, https://substackcdn.com/image/fetch/$s_!yXmQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 848w, https://substackcdn.com/image/fetch/$s_!yXmQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 1272w, https://substackcdn.com/image/fetch/$s_!yXmQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b3bbe0a-c9a2-47fe-81bb-80f982b951dc_1342x196.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Determined to find a solution, I wrote my own Python scripts to handle the scheduling process. I started by diagramming the schedule creation process.&nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Hz4w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Hz4w!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png 424w, https://substackcdn.com/image/fetch/$s_!Hz4w!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png 848w, https://substackcdn.com/image/fetch/$s_!Hz4w!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!Hz4w!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Hz4w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png" width="181" height="708.0684596577017" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1600,&quot;width&quot;:409,&quot;resizeWidth&quot;:181,&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_!Hz4w!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png 424w, https://substackcdn.com/image/fetch/$s_!Hz4w!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png 848w, https://substackcdn.com/image/fetch/$s_!Hz4w!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.png 1272w, https://substackcdn.com/image/fetch/$s_!Hz4w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83e9741e-59bd-4812-ae52-5a27c9bc7281_409x1600.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">The plan was to build something like this.</figcaption></figure></div><p>Python Code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aXPz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aXPz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png 424w, https://substackcdn.com/image/fetch/$s_!aXPz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png 848w, https://substackcdn.com/image/fetch/$s_!aXPz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png 1272w, https://substackcdn.com/image/fetch/$s_!aXPz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aXPz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png" width="1456" height="3942" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3942,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1552384,&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_!aXPz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png 424w, https://substackcdn.com/image/fetch/$s_!aXPz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png 848w, https://substackcdn.com/image/fetch/$s_!aXPz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.png 1272w, https://substackcdn.com/image/fetch/$s_!aXPz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30460ab8-9745-4021-ad8e-100b5df22cf0_1912x5176.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>However, as I ran the code, it took longer than expected.</p><p>The reason behind this is the <code>find_schedules</code>. The function is recursive and can potentially explore all combinations of courses. The time complexity can be approximated as <strong>O(K^T)</strong><em><strong>. </strong></em>If the number of target courses (k) increases, the number of potential schedules grows rapidly, leading to longer execution times.</p><p><em>P.S. If you are unfamiliar with the Big O, read it <a href="https://blog.ademartutor.com/p/understanding-big-o-notation-with">here</a>.</em></p><p>Now, it could be the reason why ChatGPT was timing out. It was possibly running a code with&nbsp; <strong>O(K^T)</strong> time complexity.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FfwZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FfwZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 424w, https://substackcdn.com/image/fetch/$s_!FfwZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 848w, https://substackcdn.com/image/fetch/$s_!FfwZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 1272w, https://substackcdn.com/image/fetch/$s_!FfwZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FfwZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png" width="572" height="153.6" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a7335149-af6f-4b19-86b6-5369991b4055_1430x384.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:384,&quot;width&quot;:1430,&quot;resizeWidth&quot;:572,&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_!FfwZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 424w, https://substackcdn.com/image/fetch/$s_!FfwZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 848w, https://substackcdn.com/image/fetch/$s_!FfwZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 1272w, https://substackcdn.com/image/fetch/$s_!FfwZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7335149-af6f-4b19-86b6-5369991b4055_1430x384.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h4><strong>O(K^T) </strong>Workaround</h4><p>I made the code work by tweaking the code and limiting the number of results.</p><p>Here&#8217;s the code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LNPr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LNPr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png 424w, https://substackcdn.com/image/fetch/$s_!LNPr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png 848w, https://substackcdn.com/image/fetch/$s_!LNPr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png 1272w, https://substackcdn.com/image/fetch/$s_!LNPr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LNPr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png" width="672" height="1897.3846153846155" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4111,&quot;width&quot;:1456,&quot;resizeWidth&quot;:672,&quot;bytes&quot;:1656594,&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_!LNPr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png 424w, https://substackcdn.com/image/fetch/$s_!LNPr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png 848w, https://substackcdn.com/image/fetch/$s_!LNPr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.png 1272w, https://substackcdn.com/image/fetch/$s_!LNPr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfb12bed-b742-4c53-8510-1b1ef1dff334_1912x5398.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><h4><strong>AI theories</strong></h4><p>After some research, I found a better way to solve the issue. How?&nbsp;By using AI theories, specifically Constraint Satisfaction Problems (CSP).</p><h5>What is CSP?</h5><p>Imagine you are planning a small dinner party with three friends: Alice, Bob, and Carol. You need to seat them around a table, but there are a few rules:</p><p>1. Alice doesn&#8217;t want to sit next to Bob.<br>2. Bob wants to sit next to Carol.<br>3. Carol doesn&#8217;t want to sit at the head of the table.</p><p>In this example:</p><ul><li><p>The variables are the seats at the table.</p></li><li><p>The possible values are Alice, Bob, and Carol.</p></li><li><p>The constraints are the seating preferences of your friends.</p></li></ul><p>A Constraint Satisfaction Problem (CSP) would help you find a seating arrangement that satisfies all these rules. For instance, you might end up with Alice, Carol, and Bob sitting in that order around the table, ensuring that all preferences are respected.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CqPn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CqPn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png 424w, https://substackcdn.com/image/fetch/$s_!CqPn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png 848w, https://substackcdn.com/image/fetch/$s_!CqPn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png 1272w, https://substackcdn.com/image/fetch/$s_!CqPn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CqPn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png" width="386" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:768,&quot;resizeWidth&quot;:386,&quot;bytes&quot;:898361,&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_!CqPn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png 424w, https://substackcdn.com/image/fetch/$s_!CqPn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png 848w, https://substackcdn.com/image/fetch/$s_!CqPn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.png 1272w, https://substackcdn.com/image/fetch/$s_!CqPn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a4557b-140b-45c9-b79c-81b80b55f013_768x768.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><h5>CSP requires three components:</h5><p>1. <strong>Variables:</strong> In the context of a class scheduling problem, the variables are the classes that need to be scheduled. Each variable (class) is associated with specific attributes, such as course name, instructor, and number of students.</p><p>2. <strong>Domains:</strong> Each variable's domain represents the possible values that can be assigned to it. The domain includes time slots, days of the week, and available rooms for class scheduling. For example, the domain of a class variable could consist of all possible time slots and room combinations.</p><p>3. <strong>Constraints:</strong> Constraints are the rules that must be followed when assigning variable values. In the class scheduling problem, typical constraints include:</p><ul><li><p><strong>Time Constraints:</strong> Ensuring that classes do not overlap for students or instructors.</p></li><li><p><strong>Room Constraints:</strong> Assigning classes to rooms that accommodate the expected number of students and have the necessary equipment.</p></li><li><p><strong>Instructor Constraints:</strong> Ensuring an instructor is not scheduled to teach two classes simultaneously and respecting their availability.</p></li><li><p><strong>Student Preferences:</strong> Accommodating preferences or requirements for specific time slots.</p></li><li><p><strong>Departmental Requirements:</strong> Meeting specific scheduling needs, such as required courses being available at particular times.</p></li></ul><p>The goal of CSP is to find an assignment of values to the variables (class scheduling) that satisfies all the constraints (requirements for each class).</p><p><em>Note: Need more information on how the CSP algorithm works? You can view this Stanford lecture series.</em></p><h4>How do you implement CSP?&nbsp;</h4><p>There&#8217;s actually a library built by Google to help you resolve the CSP problem. <a href="https://developers.google.com/optimization/cp">Google OR-Tools</a> is specifically used to solve constraint satisfaction problems (CSPs) and other combinatorial optimization problems.</p><h4>Implementing the solution</h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6AEq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6AEq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png 424w, https://substackcdn.com/image/fetch/$s_!6AEq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png 848w, https://substackcdn.com/image/fetch/$s_!6AEq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png 1272w, https://substackcdn.com/image/fetch/$s_!6AEq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6AEq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png" width="1456" height="3340" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3340,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1313465,&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_!6AEq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png 424w, https://substackcdn.com/image/fetch/$s_!6AEq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png 848w, https://substackcdn.com/image/fetch/$s_!6AEq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.png 1272w, https://substackcdn.com/image/fetch/$s_!6AEq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c45caf1-46cc-4080-a966-735fcc29acb7_1964x4506.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><h4><strong>Question: Can I create a custom CSP (Constraint Satisfaction Problem) solution, or can I just use ChatGPT to handle it?</strong></h4><p>If latency isn&#8217;t a significant concern, the critical factor here is cost.</p><p>ChatGPT&#8217;s pricing is based on the number of tokens processed, both input and output. As of writing this, the GPT-4 model costs around $0.03 per 1,000 tokens for the standard version.</p><p>After running some cost estimates with ChatGPT, handling a single scheduling problem comes to about $0.075.</p><p>For a scheduling service like Calendly, which charges $10 per month, using ChatGPT to handle scheduling tasks would allow only about 133 requests per user each month ($10 / $0.075). This is in addition to their regular server costs. The company will lose money if a user exceeds or approaches 133 requests.</p><p>In conclusion, leveraging ChatGPT can simplify development and offer powerful AI capabilities, but the cost per request could become a limiting factor. Building a custom CSP solution might involve more upfront work but could provide a more cost-effective approach in the long run.</p><p>Hope you learned something! Happy coding!</p><p><em>P.S. The complete code here: <a href="https://github.com/iamademar/class_schedule_problem">https://github.com/iamademar/class_schedule_problem</a></em></p><p></p><p></p><p></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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[Authentication with Rails and JWT]]></title><description><![CDATA[Building authentication with Rails API, Devise and JWT]]></description><link>https://blog.ademartutor.com/p/authentication-with-rails-and-jwt</link><guid isPermaLink="false">https://blog.ademartutor.com/p/authentication-with-rails-and-jwt</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Wed, 21 Feb 2024 12:23:43 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f533a1cb-7b3e-4956-8d7c-ccc1416eb65e_1280x720.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This post is an update on the <a href="https://blog.ademartutor.com/p/instrumentation-on-a-weather-api">weather_api_app</a> we built earlier.&nbsp; Our goal for this blog is to create an authentication for the back-end API using Devise Gem.<br><br>I'm assuming that the front-end and back-end of the application will be hosted on different servers, so we will use <code>rack-cors</code> to help us accept requests from different origins.</p><p>Add this to your Gemfile:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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_!Qf4W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qf4W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 424w, https://substackcdn.com/image/fetch/$s_!Qf4W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 848w, https://substackcdn.com/image/fetch/$s_!Qf4W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 1272w, https://substackcdn.com/image/fetch/$s_!Qf4W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qf4W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png" width="1276" height="410" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ae9b7747-2182-405e-a869-05044aa276d0_1276x410.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:410,&quot;width&quot;:1276,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77157,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Qf4W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 424w, https://substackcdn.com/image/fetch/$s_!Qf4W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 848w, https://substackcdn.com/image/fetch/$s_!Qf4W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 1272w, https://substackcdn.com/image/fetch/$s_!Qf4W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae9b7747-2182-405e-a869-05044aa276d0_1276x410.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Run <code>bundle install</code> and add an initializer on <code>config/initializers/cors.rb</code> </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0boh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0boh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png 424w, https://substackcdn.com/image/fetch/$s_!0boh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png 848w, https://substackcdn.com/image/fetch/$s_!0boh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png 1272w, https://substackcdn.com/image/fetch/$s_!0boh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0boh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png" width="1456" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:168925,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0boh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png 424w, https://substackcdn.com/image/fetch/$s_!0boh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png 848w, https://substackcdn.com/image/fetch/$s_!0boh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.png 1272w, https://substackcdn.com/image/fetch/$s_!0boh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e163c01-ae3f-4f73-b013-eef051ca7f31_1796x708.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></figure></div><p>The next step is to add <code>devise</code>, <code>devise-jwt</code> and <code>jsonapi-serializer</code> gem:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nFpK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nFpK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png 424w, https://substackcdn.com/image/fetch/$s_!nFpK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png 848w, https://substackcdn.com/image/fetch/$s_!nFpK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png 1272w, https://substackcdn.com/image/fetch/$s_!nFpK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nFpK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png" width="1456" height="422" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:422,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:132522,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nFpK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png 424w, https://substackcdn.com/image/fetch/$s_!nFpK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png 848w, https://substackcdn.com/image/fetch/$s_!nFpK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.png 1272w, https://substackcdn.com/image/fetch/$s_!nFpK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab0cf59-c490-430c-8cd0-49b27524ddae_1796x520.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></figure></div><h1>Setup Devise</h1><p>Do the typical <a href="https://github.com/heartcombo/devise">devise</a> installation&nbsp; and create a devise User model then do the following modifications.<br><br>Before running the devise migration, you can add the following lines:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R1mX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R1mX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 424w, https://substackcdn.com/image/fetch/$s_!R1mX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 848w, https://substackcdn.com/image/fetch/$s_!R1mX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 1272w, https://substackcdn.com/image/fetch/$s_!R1mX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R1mX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png" width="1456" height="603" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:603,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:154485,&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_!R1mX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 424w, https://substackcdn.com/image/fetch/$s_!R1mX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 848w, https://substackcdn.com/image/fetch/$s_!R1mX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 1272w, https://substackcdn.com/image/fetch/$s_!R1mX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7d4f34d-3ddd-41d4-af1f-ed393a24c4d4_1796x744.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We will be using this for the <a href="https://www.rubydoc.info/gems/devise-jwt/0.2.0/Devise/JWT/RevocationStrategies/JTIMatcher">revocation strategy</a>. Next is to add the strategy to the user model and configure it to use the correct revocation strategy:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FpRH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FpRH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 424w, https://substackcdn.com/image/fetch/$s_!FpRH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 848w, https://substackcdn.com/image/fetch/$s_!FpRH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 1272w, https://substackcdn.com/image/fetch/$s_!FpRH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FpRH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png" width="1456" height="512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:512,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:157690,&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_!FpRH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 424w, https://substackcdn.com/image/fetch/$s_!FpRH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 848w, https://substackcdn.com/image/fetch/$s_!FpRH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 1272w, https://substackcdn.com/image/fetch/$s_!FpRH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc43e5c53-e92a-425c-86e3-5fcc740b27b2_1796x632.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h1>Setup devise-jwt</h1><p>Set up a secret we will be using for JWT. On the terminal do this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wa4v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wa4v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 424w, https://substackcdn.com/image/fetch/$s_!wa4v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 848w, https://substackcdn.com/image/fetch/$s_!wa4v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 1272w, https://substackcdn.com/image/fetch/$s_!wa4v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wa4v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png" width="1456" height="340" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:340,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83698,&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_!wa4v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 424w, https://substackcdn.com/image/fetch/$s_!wa4v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 848w, https://substackcdn.com/image/fetch/$s_!wa4v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 1272w, https://substackcdn.com/image/fetch/$s_!wa4v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7e07f80-91a2-4476-84f1-a442c32a4c0b_1796x420.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Save the key on an ENV variable. In my case, I'm saving the variable as <code>DEVISE_JWT_SECRET_KEY</code>.</p><p>Update config/initializers/devise.rb:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qw-D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qw-D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 424w, https://substackcdn.com/image/fetch/$s_!qw-D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 848w, https://substackcdn.com/image/fetch/$s_!qw-D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 1272w, https://substackcdn.com/image/fetch/$s_!qw-D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qw-D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png" width="1456" height="725" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:725,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:187930,&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_!qw-D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 424w, https://substackcdn.com/image/fetch/$s_!qw-D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 848w, https://substackcdn.com/image/fetch/$s_!qw-D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 1272w, https://substackcdn.com/image/fetch/$s_!qw-D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F45ad6bed-c923-4558-9eca-55ff1e77e4dd_1796x894.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h1>Setup <strong>jsonapi_serializer</strong></h1><p>Generate the serializer that we will be using later when we update the devise controllers so we return a json:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e09e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e09e!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 424w, https://substackcdn.com/image/fetch/$s_!e09e!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 848w, https://substackcdn.com/image/fetch/$s_!e09e!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 1272w, https://substackcdn.com/image/fetch/$s_!e09e!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e09e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png" width="1456" height="340" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:340,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84899,&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_!e09e!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 424w, https://substackcdn.com/image/fetch/$s_!e09e!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 848w, https://substackcdn.com/image/fetch/$s_!e09e!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 1272w, https://substackcdn.com/image/fetch/$s_!e09e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51a2d78a-8f6e-4271-9b15-e7daf6a9c89a_1796x420.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><h1>Update Devise controllers</h1><p>Update the Registration controller to respond to JSON requests</p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mE90!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mE90!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 424w, https://substackcdn.com/image/fetch/$s_!mE90!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 848w, https://substackcdn.com/image/fetch/$s_!mE90!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 1272w, https://substackcdn.com/image/fetch/$s_!mE90!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mE90!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png" width="1456" height="905" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:905,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:288235,&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_!mE90!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 424w, https://substackcdn.com/image/fetch/$s_!mE90!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 848w, https://substackcdn.com/image/fetch/$s_!mE90!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 1272w, https://substackcdn.com/image/fetch/$s_!mE90!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f44dbd8-c596-43b5-9dee-95c4f8c80509_2220x1380.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Update the Session controller to respond to JSON requests</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_mUP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_mUP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png 424w, https://substackcdn.com/image/fetch/$s_!_mUP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png 848w, https://substackcdn.com/image/fetch/$s_!_mUP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png 1272w, https://substackcdn.com/image/fetch/$s_!_mUP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_mUP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png" width="1456" height="1099" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1099,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:382862,&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_!_mUP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png 424w, https://substackcdn.com/image/fetch/$s_!_mUP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png 848w, https://substackcdn.com/image/fetch/$s_!_mUP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.png 1272w, https://substackcdn.com/image/fetch/$s_!_mUP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc6515a72-3eb6-4fb5-ba17-00c172e0b3c2_2220x1676.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>If you try out the API you will encounter this error:</p><pre><code>ActionDispatch::Request::Session::DisabledSessionError (Your application has sessions disabled. To write to the session you must first configure a session store):</code></pre><p>This is because the Rails application session store is not configured properly.&nbsp;<br><br>You can configure it by add a `config/initiliazers/session_store.rb` file. Then add this line:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YkR_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YkR_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 424w, https://substackcdn.com/image/fetch/$s_!YkR_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 848w, https://substackcdn.com/image/fetch/$s_!YkR_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 1272w, https://substackcdn.com/image/fetch/$s_!YkR_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YkR_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png" width="1456" height="293" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:293,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:114810,&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_!YkR_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 424w, https://substackcdn.com/image/fetch/$s_!YkR_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 848w, https://substackcdn.com/image/fetch/$s_!YkR_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 1272w, https://substackcdn.com/image/fetch/$s_!YkR_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24d0ce08-044a-4b26-9ac5-b9b5b7eea3ce_2220x446.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>On the `config/application.rb`, add the following lines:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ReqC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ReqC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 424w, https://substackcdn.com/image/fetch/$s_!ReqC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 848w, https://substackcdn.com/image/fetch/$s_!ReqC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 1272w, https://substackcdn.com/image/fetch/$s_!ReqC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ReqC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png" width="1456" height="701" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:701,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:209822,&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_!ReqC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 424w, https://substackcdn.com/image/fetch/$s_!ReqC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 848w, https://substackcdn.com/image/fetch/$s_!ReqC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 1272w, https://substackcdn.com/image/fetch/$s_!ReqC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ef169de-ef4b-4bc8-8fa6-f0a75bf64b8e_1700x818.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h1>Testing with Postman</h1><p>User Registration</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;1cfedf76-d8c9-4d83-a5ec-4bb1a18eb63c&quot;,&quot;duration&quot;:null}"></div><p>User Login</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;2fd2bdf3-4c59-4623-a74b-56aeafa8b8f0&quot;,&quot;duration&quot;:null}"></div><p>Accessing weather endpoint with logged-in user</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;9c980f9b-ef56-4674-8a5b-535ea53d2658&quot;,&quot;duration&quot;:null}"></div><p><br>User logout and accessing weather endpoint</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;a5fdfdea-ed2b-4c31-a3d2-d20e4d986668&quot;,&quot;duration&quot;:null}"></div><p></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p>]]></content:encoded></item><item><title><![CDATA[Instrumentation on a Weather API app using Rails, OpenTelemetry, and Jaeger]]></title><description><![CDATA[Building instrumentation code with OpenTelemetry and Jaeger on a Rails API app.]]></description><link>https://blog.ademartutor.com/p/instrumentation-on-a-weather-api</link><guid isPermaLink="false">https://blog.ademartutor.com/p/instrumentation-on-a-weather-api</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Tue, 20 Feb 2024 11:17:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1790e380-d142-4d26-8c00-3ec99db5d3ed_1280x720.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We've previously discussed <a href="https://blog.ademartutor.com/p/observability-with-opentelemetry">Rails with OpenTelemetry and Jaeger</a>. In this blog, let's discuss how we can build a simple Rails API that serves weather data. OpenTelemetry and Jaeger will observe this application with custom instrumentation.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YI9N!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YI9N!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 424w, https://substackcdn.com/image/fetch/$s_!YI9N!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 848w, https://substackcdn.com/image/fetch/$s_!YI9N!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 1272w, https://substackcdn.com/image/fetch/$s_!YI9N!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YI9N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png" width="1456" height="1334" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1334,&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;: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_!YI9N!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 424w, https://substackcdn.com/image/fetch/$s_!YI9N!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 848w, https://substackcdn.com/image/fetch/$s_!YI9N!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 1272w, https://substackcdn.com/image/fetch/$s_!YI9N!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ff50a12-787b-41e3-884c-c9fadd5d02e2_1688x1546.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h6><em>Screenshot sourced from <a href="https://www.behance.net/gallery/169457873/Fairy-weather-forecast-mobile-web-progressive-app/modules/1061991269">Behance</a>.</em></h6><h1>Step 1: Rails Application Setup</h1><p><strong>Create new Rails API app</strong><br>Run <code>rails new weather_api_app --api</code> to create a new Rails API application. The <code>--api</code><strong> </strong>flag tells Rails to set up the application specifically for an API.<br><br><em>I'm assuming you already have Rails in your system.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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></p><p><strong>Add Dependencies</strong></p><p>Install the following gems to your Gemfile:</p><p>&#128142; httparty - Responsible for making HTTP requests to the OpenWeatherMap API.<br>&#128142; opentelemetry-sdk, opentelemetry-exporter-otlp, opentelemetry-instrumentation-all - OpenTelemetry gems for <a href="https://blog.ademartutor.com/p/observability-with-opentelemetry">observability</a>.&nbsp; You can learn about how to set them up <a href="https://blog.ademartutor.com/p/observability-with-opentelemetry">here</a>.</p><h1>Step 2: Weather Data Retrieval</h1><p>Generate Controller</p><pre><code>rails g controller Weather show</code></pre><p>Update the WeatherController code</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fEso!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fEso!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 424w, https://substackcdn.com/image/fetch/$s_!fEso!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 848w, https://substackcdn.com/image/fetch/$s_!fEso!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 1272w, https://substackcdn.com/image/fetch/$s_!fEso!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fEso!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png" width="1456" height="698" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:698,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:221035,&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_!fEso!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 424w, https://substackcdn.com/image/fetch/$s_!fEso!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 848w, https://substackcdn.com/image/fetch/$s_!fEso!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 1272w, https://substackcdn.com/image/fetch/$s_!fEso!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ce9b578-ca53-402f-a6f2-123b2953be60_2020x968.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The routes should look like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6WtX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6WtX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png 424w, https://substackcdn.com/image/fetch/$s_!6WtX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png 848w, https://substackcdn.com/image/fetch/$s_!6WtX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png 1272w, https://substackcdn.com/image/fetch/$s_!6WtX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6WtX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png" width="1312" height="558" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/df485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:558,&quot;width&quot;:1312,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121438,&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_!6WtX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png 424w, https://substackcdn.com/image/fetch/$s_!6WtX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png 848w, https://substackcdn.com/image/fetch/$s_!6WtX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.png 1272w, https://substackcdn.com/image/fetch/$s_!6WtX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf485f38-6ab2-4e9c-9bfe-385e6a01cb0d_1312x558.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>You can now fetch data from the API using&nbsp; a CURL request (or use Postman):</p><pre><code>curl "http://localhost:3000/weather/show?city=Colombo"</code></pre><p>That's the simplest way of requesting data from OpenWeatherMap API.</p><p></p><div><hr></div><p></p><h2>&#128640;&nbsp; Refactoring the code to follow the Single Responsibility Principle</h2><p>What we will do here is keep our controllers slim and focused only on handling web requests. Moving the API request logic into a service.</p><p></p><p>Here's how you do it:</p><h3>1. Create a PORO for Fetching Weather Data</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rpCc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rpCc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 424w, https://substackcdn.com/image/fetch/$s_!rpCc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 848w, https://substackcdn.com/image/fetch/$s_!rpCc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 1272w, https://substackcdn.com/image/fetch/$s_!rpCc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rpCc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png" width="1456" height="861" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:861,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:279968,&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_!rpCc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 424w, https://substackcdn.com/image/fetch/$s_!rpCc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 848w, https://substackcdn.com/image/fetch/$s_!rpCc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 1272w, https://substackcdn.com/image/fetch/$s_!rpCc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92ea94ac-0f5b-4efd-8877-d100563777ea_2076x1228.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>2. Update the WeatherController</h3><p>Modify your <code>WeatherController</code> to use this new <code>WeatherFetcher</code> service:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tCcI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tCcI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 424w, https://substackcdn.com/image/fetch/$s_!tCcI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 848w, https://substackcdn.com/image/fetch/$s_!tCcI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 1272w, https://substackcdn.com/image/fetch/$s_!tCcI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tCcI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png" width="1456" height="475" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:475,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:207539,&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_!tCcI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 424w, https://substackcdn.com/image/fetch/$s_!tCcI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 848w, https://substackcdn.com/image/fetch/$s_!tCcI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 1272w, https://substackcdn.com/image/fetch/$s_!tCcI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F143e8d23-9371-4274-9921-2d02a5e1e736_2508x818.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>With the OpenTelemetry and Jaeger setup, you can observe your application like the video below.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;b538e82b-bdbe-4260-9765-387b92f53573&quot;,&quot;duration&quot;:null}"></div><p></p><h1>Step 3: Instrumentation with OpenTelemetry</h1><p>What is instrumentation? Instrumentation is the act of adding observability code to the app yourself. The simple analogy is like adding `logger.info` but sending the data to OpenTelemetry and Jaeger instead of the console.</p><h3>Global Tracer</h3><p>The first thing we need to do is to acquire a Tracer from the `config/initializers/opentelemetry.rb`:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xzdq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xzdq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png 424w, https://substackcdn.com/image/fetch/$s_!xzdq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png 848w, https://substackcdn.com/image/fetch/$s_!xzdq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png 1272w, https://substackcdn.com/image/fetch/$s_!xzdq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xzdq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png" width="1456" height="594" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c82725e1-8494-44b1-a076-a705110793ca_2004x818.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:594,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:202328,&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_!xzdq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png 424w, https://substackcdn.com/image/fetch/$s_!xzdq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png 848w, https://substackcdn.com/image/fetch/$s_!xzdq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.png 1272w, https://substackcdn.com/image/fetch/$s_!xzdq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc82725e1-8494-44b1-a076-a705110793ca_2004x818.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 "Tracer" will be globally available to any part of the app.</p><h3>Adding a Span</h3><p>We want to add a new span to break down the execution of a process into smaller, measurable units. In this case, we want to isolate the OpenWeatherMap request.</p><p>On the `app/services/weather_fetcher.rb`, let's add code to create a new span on the fetch method:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x5jq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x5jq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 424w, https://substackcdn.com/image/fetch/$s_!x5jq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 848w, https://substackcdn.com/image/fetch/$s_!x5jq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 1272w, https://substackcdn.com/image/fetch/$s_!x5jq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x5jq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png" width="1456" height="433" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:433,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:138182,&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_!x5jq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 424w, https://substackcdn.com/image/fetch/$s_!x5jq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 848w, https://substackcdn.com/image/fetch/$s_!x5jq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 1272w, https://substackcdn.com/image/fetch/$s_!x5jq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd418ec96-c2c8-4177-beda-89be527db2a0_2004x596.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Adding an Event</h3><p>On the private method `fetch`, let's add an event. To signify during the start and end of the OpenWeatherMap API request.</p><p>What's an event?&nbsp;</p><blockquote><p>A <a href="https://opentelemetry.io/docs/concepts/signals/traces#span-events">span event</a> is a human-readable message on a span that represents &#8220;something happening&#8221; during it&#8217;s lifetime.</p></blockquote><p>On the `app/services/weather_fetcher.rb`, let's update the fetch method:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zmcX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zmcX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 424w, https://substackcdn.com/image/fetch/$s_!zmcX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 848w, https://substackcdn.com/image/fetch/$s_!zmcX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 1272w, https://substackcdn.com/image/fetch/$s_!zmcX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zmcX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png" width="1456" height="594" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:594,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:256527,&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_!zmcX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 424w, https://substackcdn.com/image/fetch/$s_!zmcX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 848w, https://substackcdn.com/image/fetch/$s_!zmcX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 1272w, https://substackcdn.com/image/fetch/$s_!zmcX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa27c68f3-9d10-483a-a0cb-3f36927d7ac6_2004x818.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The new weather_fetcher.rb with instrumentation should look like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fuez!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fuez!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png 424w, https://substackcdn.com/image/fetch/$s_!fuez!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png 848w, https://substackcdn.com/image/fetch/$s_!fuez!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png 1272w, https://substackcdn.com/image/fetch/$s_!fuez!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fuez!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png" width="1456" height="1031" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1031,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:382094,&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_!fuez!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png 424w, https://substackcdn.com/image/fetch/$s_!fuez!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png 848w, https://substackcdn.com/image/fetch/$s_!fuez!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.png 1272w, https://substackcdn.com/image/fetch/$s_!fuez!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5cd7cfb-d3d2-4837-abc8-45911120c9aa_2104x1490.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>You should be able to see the changes on the new span and event on Jaeger UI.</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;cde55694-93dd-498d-ae50-22a591a25f8b&quot;,&quot;duration&quot;:null}"></div><p></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p>]]></content:encoded></item><item><title><![CDATA[Observability with OpenTelemetry, Jaeger and Rails]]></title><description><![CDATA[Discussion and setup of OpenTelemetry and Jaeger with Ruby on Rails]]></description><link>https://blog.ademartutor.com/p/observability-with-opentelemetry</link><guid isPermaLink="false">https://blog.ademartutor.com/p/observability-with-opentelemetry</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Mon, 19 Feb 2024 12:25:40 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/bd8e9eb5-d817-483b-b47d-a96b04b6b004_1280x720.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In a traditional monolithic architecture, the application's behavior is relatively straightforward because all components reside within a single process. You can easily trace requests from their entry to their exit points.</p><p>However, in a microservices architecture, a single transaction or request might pass through many services hosted on different machines or across different data centers. This dispersion makes it hard to "observe."</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building Apps for Startups with Ademar Tutor! 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>Does it apply to a Rails monolith?</h2><p>Yes, it does!&nbsp;<br><br>Let's say you are working on an e-commerce application. You are fixing a production bug for the checkout workflow on this application. </p><p>The workflow includes the following actions:</p><ul><li><p>Charging credit cards via a 3rd party payment gateway (Stripe, Braintree and etc.)</p></li><li><p>Sending a customer an email notification (Sendgrid, Twilio)</p></li><li><p>Send updates to your order management system responsible for handling your inventory.</p></li></ul><p>The bug only arises during peak hours.&nbsp;<br><br>This would only mean that one or two of the processes took too long to respond and caused the entire workflow to fail.&nbsp;<br><br>You do not monitor your Rails application's internal components, but you must also monitor the interactions with these external services.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!E422!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!E422!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 424w, https://substackcdn.com/image/fetch/$s_!E422!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 848w, https://substackcdn.com/image/fetch/$s_!E422!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 1272w, https://substackcdn.com/image/fetch/$s_!E422!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!E422!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png" width="1288" height="1274" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1274,&quot;width&quot;:1288,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84459,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!E422!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 424w, https://substackcdn.com/image/fetch/$s_!E422!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 848w, https://substackcdn.com/image/fetch/$s_!E422!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 1272w, https://substackcdn.com/image/fetch/$s_!E422!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5cbbaee9-2bc9-41dc-a660-0978a3ace456_1288x1274.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><br><br>This is where OpenTelemetry comes in.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NYWP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NYWP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 424w, https://substackcdn.com/image/fetch/$s_!NYWP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 848w, https://substackcdn.com/image/fetch/$s_!NYWP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!NYWP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NYWP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png" width="1456" height="1104" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1104,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:92137,&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_!NYWP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 424w, https://substackcdn.com/image/fetch/$s_!NYWP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 848w, https://substackcdn.com/image/fetch/$s_!NYWP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 1272w, https://substackcdn.com/image/fetch/$s_!NYWP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62f24cda-1ca4-449c-861e-666116cf059a_1688x1280.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><br>What is OpenTelemetry?</h2><p><br>OpenTelemetry is an open-source observability framework that helps you gather metrics, traces, and logs.</p><h4>Why do I need that? I already have New Relic, Skylight, and AppSignal.</h4><p>OpenTelemetry is vendor-neutral. It doesn't lock you into a specific observability platform. You can switch to another vendor. Plus, OpenTelemetry is incubated by <a href="https://www.cncf.io/projects/">CNCF</a> and is supported by <a href="https://opentelemetry.io/ecosystem/vendors/">industry leaders</a>. This means it's here to stay!</p><p></p><h4>Would OpenTelemetry replace New Relic, Skylight, and AppSignal?</h4><p>OpenTelemetry specifies how data should be structured, collected, and sent over the network, but it doesn't provide a backend system to store, visualize, or analyze this data.&nbsp;<br><br>You can send this data to New Relic or AppSignal to store, visualize, or analyze.&nbsp;<br><br>But you can set up open-source solutions to view your data. This is where Jaeger comes in.</p><blockquote><p>Jaeger maps the flow of requests and data as they traverse a distributed system. These requests may make calls to multiple services, which may introduce their own delays or errors. </p><p><a href="https://www.jaegertracing.io/">https://www.jaegertracing.io/</a></p></blockquote><p></p><h3>How do you set up OpenTelemetry + Jaeger with a Ruby on Rails application?</h3><p></p><p>These are the step-by-step process for integrating OpenTelemetry and Jaeger with your Ruby on Rails app.</p><p></p><h5>1) Install the necessary gems</h5><pre><code>gem "opentelemetry-sdk"
gem "opentelemetry-exporter-otlp"
gem "opentelemetry-instrumentation-all"</code></pre><h5></h5><h5>2) Run Rails app and set the tracer exporter to console.</h5><pre><code>env OTEL_TRACES_EXPORTER=console rails server</code></pre><p><br>Now, see if you can see the logs on the server. The logs should show something like this:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;e1bbed6e-025a-4d6a-96eb-0e64a5218c20&quot;,&quot;duration&quot;:null}"></div><p><br>3) You can then set up a Jaeger backend to pass data. You can do that by running this image on your terminal:</p><pre><code>docker run -d --name jaeger \
  -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:latest</code></pre><p>You will see the Jaeger on your docker desktop. You need to make sure the container is running.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G0aI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G0aI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png 424w, https://substackcdn.com/image/fetch/$s_!G0aI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png 848w, https://substackcdn.com/image/fetch/$s_!G0aI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png 1272w, https://substackcdn.com/image/fetch/$s_!G0aI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G0aI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png" width="1456" height="796" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:796,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:425685,&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_!G0aI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png 424w, https://substackcdn.com/image/fetch/$s_!G0aI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png 848w, https://substackcdn.com/image/fetch/$s_!G0aI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.png 1272w, https://substackcdn.com/image/fetch/$s_!G0aI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfe13c4d-15f4-42a5-803d-0378772ce625_2538x1388.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>Once it's running you should be able to access the Jaeger UI on your browser via <a href="http://localhost:16686/search">http://localhost:16686/search</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R8E6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R8E6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 424w, https://substackcdn.com/image/fetch/$s_!R8E6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 848w, https://substackcdn.com/image/fetch/$s_!R8E6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 1272w, https://substackcdn.com/image/fetch/$s_!R8E6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R8E6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png" width="1456" height="1154" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1154,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:324845,&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_!R8E6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 424w, https://substackcdn.com/image/fetch/$s_!R8E6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 848w, https://substackcdn.com/image/fetch/$s_!R8E6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 1272w, https://substackcdn.com/image/fetch/$s_!R8E6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F788c64e1-d110-44b1-8ac0-c5ba71cc87e1_2140x1696.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>By default, traces are sent to an OTLP endpoint listening on localhost:4318. Your rails app should be set up automatically. However, if you need to update the endpoint, you can set it up manually by adding an ENV variable. </p><pre><code>env OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318" rails server</code></pre><p>You should be able to see the request on Jaeger UI:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;e3c5cc59-d10e-4e0d-84c9-28589d6faa4d&quot;,&quot;duration&quot;:null}"></div><p><br></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p>]]></content:encoded></item><item><title><![CDATA[Callbacks are evil! 😈]]></title><description><![CDATA[Discussing the pros and cons of using ActiveRecord Callbacks with real world experiences.]]></description><link>https://blog.ademartutor.com/p/callbacks-are-evil</link><guid isPermaLink="false">https://blog.ademartutor.com/p/callbacks-are-evil</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Wed, 07 Feb 2024 06:17:17 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/81be2096-b360-4b18-90f9-661c36e9753f_1280x720.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GsYH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GsYH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!GsYH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!GsYH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!GsYH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GsYH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg" width="1280" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:107962,&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_!GsYH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!GsYH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!GsYH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!GsYH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b56323a-2ad0-4ac9-8242-251fe27b7bfb_1280x720.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>I&#8217;m working on a super secret app to revolutionize service field businesses &#128540;. Yesterday, the codebase had the opportunity to be viewed by eyes from the outside world for the first time and got feedback.</p><p>One of the things that stood out was the code related to converting Requests to Quotes. This workflow:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building AI Apps for Startups with Ademar Tutor! 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_!k7ve!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k7ve!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!k7ve!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!k7ve!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!k7ve!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k7ve!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3914578,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k7ve!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!k7ve!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!k7ve!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!k7ve!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9b3fe9-2e73-4838-8f9e-f551dc82de45_1920x1080.gif 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></figure></div><p></p><p>This particular code:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2vAt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2vAt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png 424w, https://substackcdn.com/image/fetch/$s_!2vAt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png 848w, https://substackcdn.com/image/fetch/$s_!2vAt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png 1272w, https://substackcdn.com/image/fetch/$s_!2vAt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2vAt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png" width="1430" height="930" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:930,&quot;width&quot;:1430,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:178277,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2vAt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png 424w, https://substackcdn.com/image/fetch/$s_!2vAt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png 848w, https://substackcdn.com/image/fetch/$s_!2vAt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.png 1272w, https://substackcdn.com/image/fetch/$s_!2vAt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822c9e75-6b66-4b50-8e74-035786669b5f_1430x930.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></figure></div><p>This involved the callback <code>after_create!</code></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WF6G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WF6G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif 424w, https://substackcdn.com/image/fetch/$s_!WF6G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif 848w, https://substackcdn.com/image/fetch/$s_!WF6G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif 1272w, https://substackcdn.com/image/fetch/$s_!WF6G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WF6G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif" width="395" height="498" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:498,&quot;width&quot;:395,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:703425,&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;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WF6G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif 424w, https://substackcdn.com/image/fetch/$s_!WF6G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif 848w, https://substackcdn.com/image/fetch/$s_!WF6G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.gif 1272w, https://substackcdn.com/image/fetch/$s_!WF6G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83db7b3a-386a-4e8c-a6ba-ed6eecf8c091_395x498.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></p><p>I know, I know. <a href="https://medium.com/planet-arkency/the-biggest-rails-code-smell-you-should-avoid-to-keep-your-app-healthy-a61fd75ab2d3">Callbacks are evil!</a></p><p>Well, my lame excuse at the time of development is I could not find the correct language for the conversion process when developing the <a href="https://thedomaindrivendesign.io/developing-the-ubiquitous-language/">ubiquitous language</a>.</p><p>Based on the stakeholders, whenever they need the quote to be produced, they just say to the employee: &#8220;Palihug ko pa.quote ani dong/dai. &#8220;</p><p>This can be loosely translated as: &#8220;Hey [name], can you please create a quote for this customer&#8217;s request?&#8221;</p><p>At that time of development, I could not find the right words for it. Based on what I was hearing from the stakeholders, they just said to create a quote. </p><p>So, I opted for the easiest solution available, callbacks!</p><h2>Why are callbacks bad?</h2><p>It is probably not that concerning in this particular case since the workflow is pretty simple.</p><p>However, I&#8217;ve been burned by this before! When I was working on an e-commerce application, we used a <code>after_save</code> callback that sent app notifications to listing owners when their listings were updated. When we ran a script that was intended to update silently thousands of listings on a Sunday evening. Long story short, it was not a very silent Sunday &#128517;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5I1h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5I1h!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5I1h!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5I1h!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5I1h!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5I1h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg" width="650" height="602" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:602,&quot;width&quot;:650,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Securing Non-Production Environments&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="Securing Non-Production Environments" title="Securing Non-Production Environments" srcset="https://substackcdn.com/image/fetch/$s_!5I1h!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5I1h!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5I1h!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5I1h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6638eaec-3af8-4fc5-98b9-0bd3488fa598_650x602.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><h2>So, how do we move away from callbacks?</h2><p>Modeling/developing/writing a better ubiquitous language for the domain you are working on helps you write better code.</p><p>In my case, I could not find the right technical words while conversing with the stakeholders.</p><p>However, now that I started developing the user interface, it seems it&#8217;s pretty straightforward:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F9Zt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F9Zt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 424w, https://substackcdn.com/image/fetch/$s_!F9Zt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 848w, https://substackcdn.com/image/fetch/$s_!F9Zt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 1272w, https://substackcdn.com/image/fetch/$s_!F9Zt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F9Zt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png" width="263" height="133" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:133,&quot;width&quot;:263,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:14121,&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_!F9Zt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 424w, https://substackcdn.com/image/fetch/$s_!F9Zt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 848w, https://substackcdn.com/image/fetch/$s_!F9Zt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 1272w, https://substackcdn.com/image/fetch/$s_!F9Zt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6627f21-4ac8-4119-96f2-6dce057e6fae_263x133.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><h2>So, what does the change look like in the code?</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qdt4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qdt4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 424w, https://substackcdn.com/image/fetch/$s_!qdt4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 848w, https://substackcdn.com/image/fetch/$s_!qdt4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 1272w, https://substackcdn.com/image/fetch/$s_!qdt4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qdt4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png" width="749" height="625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:749,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24231,&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_!qdt4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 424w, https://substackcdn.com/image/fetch/$s_!qdt4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 848w, https://substackcdn.com/image/fetch/$s_!qdt4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 1272w, https://substackcdn.com/image/fetch/$s_!qdt4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F77647ae2-2ac9-4d3d-ba35-b96b30abb47c_749x625.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2></h2><p></p><p><strong>Step 1: Create a PORO to handle the business logic</strong></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qd8-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qd8-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png 424w, https://substackcdn.com/image/fetch/$s_!Qd8-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png 848w, https://substackcdn.com/image/fetch/$s_!Qd8-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png 1272w, https://substackcdn.com/image/fetch/$s_!Qd8-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qd8-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png" width="1076" height="1414" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1414,&quot;width&quot;:1076,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:229393,&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_!Qd8-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png 424w, https://substackcdn.com/image/fetch/$s_!Qd8-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png 848w, https://substackcdn.com/image/fetch/$s_!Qd8-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.png 1272w, https://substackcdn.com/image/fetch/$s_!Qd8-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e048862-9e42-462d-95f2-cfb03543347c_1076x1414.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>Things to note on the code above:</p><ul><li><p>I created a PORO (Plain Old Ruby Object) for the Request to Quote Conversion business logic. </p></li><li><p>Later, if we want to send email or mobile notifications to admins or employees, we should update this class. </p></li><li><p>If anything fails, this class should handle the failure gracefully, especially if it involves payments, etc.</p></li><li><p>Now that it&#8217;s a class, creating unit tests for this specific business logic would be easier, ensuring that this process is more robust when change requests come in later.</p></li></ul><p></p><p><strong>Step 2: Update controllers</strong></p><p>You can then use the PORO on the controller like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yfEn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yfEn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png 424w, https://substackcdn.com/image/fetch/$s_!yfEn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png 848w, https://substackcdn.com/image/fetch/$s_!yfEn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png 1272w, https://substackcdn.com/image/fetch/$s_!yfEn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yfEn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png" width="1380" height="894" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18624676-d69e-4a5e-8482-209c520fb333_1380x894.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:894,&quot;width&quot;:1380,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:190642,&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_!yfEn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png 424w, https://substackcdn.com/image/fetch/$s_!yfEn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png 848w, https://substackcdn.com/image/fetch/$s_!yfEn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.png 1272w, https://substackcdn.com/image/fetch/$s_!yfEn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18624676-d69e-4a5e-8482-209c520fb333_1380x894.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><strong>Optional Steps:</strong></p><p>You can actually do it a step further and follow <a href="https://www.youtube.com/playlist?list=PL3m89j0mV0pdNAg6x9oq6S8Qz_4C-yuwj">DHH&#8217;s approach</a>, creating a method for the request model:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0RGe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0RGe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png 424w, https://substackcdn.com/image/fetch/$s_!0RGe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png 848w, https://substackcdn.com/image/fetch/$s_!0RGe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png 1272w, https://substackcdn.com/image/fetch/$s_!0RGe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0RGe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png" width="1076" height="782" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:782,&quot;width&quot;:1076,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:156008,&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_!0RGe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png 424w, https://substackcdn.com/image/fetch/$s_!0RGe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png 848w, https://substackcdn.com/image/fetch/$s_!0RGe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.png 1272w, https://substackcdn.com/image/fetch/$s_!0RGe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27a37046-0f69-43b1-9c7d-fb3c8603d633_1076x782.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>Then, you can easily create a call this method on the controller like so:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CSZz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CSZz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 424w, https://substackcdn.com/image/fetch/$s_!CSZz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 848w, https://substackcdn.com/image/fetch/$s_!CSZz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 1272w, https://substackcdn.com/image/fetch/$s_!CSZz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CSZz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png" width="1456" height="728" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8658094f-0142-420e-95ef-8d85751a0981_1564x782.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:728,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:179184,&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_!CSZz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 424w, https://substackcdn.com/image/fetch/$s_!CSZz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 848w, https://substackcdn.com/image/fetch/$s_!CSZz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 1272w, https://substackcdn.com/image/fetch/$s_!CSZz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8658094f-0142-420e-95ef-8d85751a0981_1564x782.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now, the code is more readable and safer in the future!</p><h2>Question: Are callbacks evil?</h2><p>There are two camps for this, people who are <a href="https://dev.37signals.com/globals-callbacks-and-other-sacrileges/">for</a> and <a href="https://medium.com/planet-arkency/the-biggest-rails-code-smell-you-should-avoid-to-keep-your-app-healthy-a61fd75ab2d3">against</a> callbacks.</p><p>So which camp do I align? <br><br>My take is:<br>As developers, we are constantly understanding the domains that we are working on and developing a unique <a href="https://thedomaindrivendesign.io/developing-the-ubiquitous-language/">ubiquitous language</a> for them. </p><p>Initially, we may not have the right words for it, thus we need to use convenient &#8220;generic&#8221; tools such as callbacks. But as soon as you learn more about the domain, and build a better ubiquitous language, the design of your code should follow also.</p><p></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p><p></p><p></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Building an AI chatbot to handle Amazon’s Help & Customer Service]]></title><description><![CDATA[Build a chatbot using vector search, OpenAI and langchainrb]]></description><link>https://blog.ademartutor.com/p/building-an-ai-chatbot-to-handle</link><guid isPermaLink="false">https://blog.ademartutor.com/p/building-an-ai-chatbot-to-handle</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Mon, 22 Jan 2024 16:54:55 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c5c71f5c-e0ec-47fb-b4a9-fa75857cdbd3_1280x720.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In 2023, Amazon had a revenue of $554.03B. Considering the scale of Amazon's operations and the complexity of its services, it's reasonable to speculate that its spending on customer support is likely to be a significant figure, potentially running into millions of dollars.</p><h2>Objective</h2><p>Our objective in this blog is to create a chatbot that is an expert in Amazon&#8217;s Help &amp; Customer Service. The chatbot should be able to answer queries from <a href="https://www.amazon.com/gp/help/customer/display.html">Amazon&#8217;s Customer Service Page</a>. Hopefully, this app will help Amazon save a couple of million dollars in Customer Support spending &#128517;.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building AI Apps for Startups with Ademar Tutor! 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>On this blog, our limitation is that we will only build the back end of the chatbot. We&#8217;ll do UI and other improvements later.</p><p></p><h2>Tech Stack</h2><ul><li><p><strong>PostgreSQL</strong> - We&#8217;ll use PostgreSQL with a vector search extension. Why use PostgreSQL? PostgreSQL is mature and well-established, which means it has a wide range of features, strong community support, and extensive documentation.</p></li><li><p><strong>pgvector </strong>- What is pgvector? pgvector is a PostgreSQL extension for vector similarity search.</p></li><li><p><strong>langchainrb_rails - </strong>Think of it as searchkick for elasticsearch, but this gem is specifically for AI.</p></li><li><p><strong>langchainrb - </strong>Think of it as a framework for integrating AI with Ruby applications.</p></li><li><p><strong>neighbor -</strong> This gem is responsible with vector search in PostgreSQL.</p></li><li><p><strong>OpenAI</strong> - Large Language Model that we will use.</p></li></ul><p></p><h2>Workflow</h2><p>This is the workflow of how we&#8217;ll get the embedding for the Policy model.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C82K!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C82K!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 424w, https://substackcdn.com/image/fetch/$s_!C82K!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 848w, https://substackcdn.com/image/fetch/$s_!C82K!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 1272w, https://substackcdn.com/image/fetch/$s_!C82K!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C82K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png" width="1289" height="865" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:865,&quot;width&quot;:1289,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57039,&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_!C82K!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 424w, https://substackcdn.com/image/fetch/$s_!C82K!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 848w, https://substackcdn.com/image/fetch/$s_!C82K!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 1272w, https://substackcdn.com/image/fetch/$s_!C82K!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbfe9ba30-3fd3-4f1e-9c47-76bc17bf7285_1289x865.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>This is the workflow of how we&#8217;ll ask a question.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aky5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aky5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 424w, https://substackcdn.com/image/fetch/$s_!aky5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 848w, https://substackcdn.com/image/fetch/$s_!aky5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 1272w, https://substackcdn.com/image/fetch/$s_!aky5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aky5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png" width="1289" height="865" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:865,&quot;width&quot;:1289,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:66115,&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_!aky5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 424w, https://substackcdn.com/image/fetch/$s_!aky5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 848w, https://substackcdn.com/image/fetch/$s_!aky5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 1272w, https://substackcdn.com/image/fetch/$s_!aky5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52402c3c-1b54-4394-aea2-81be3e1930f0_1289x865.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>Implementation</h2><h4>Step 1</h4><p>Let&#8217;s create a new rails app.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nQ_h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nQ_h!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png 424w, https://substackcdn.com/image/fetch/$s_!nQ_h!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png 848w, https://substackcdn.com/image/fetch/$s_!nQ_h!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png 1272w, https://substackcdn.com/image/fetch/$s_!nQ_h!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nQ_h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png" width="874" height="420" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:420,&quot;width&quot;:874,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80308,&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_!nQ_h!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png 424w, https://substackcdn.com/image/fetch/$s_!nQ_h!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png 848w, https://substackcdn.com/image/fetch/$s_!nQ_h!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.png 1272w, https://substackcdn.com/image/fetch/$s_!nQ_h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0f14fc10-60e5-4b8e-bbb4-80f9d5998e38_874x420.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><h4><br>Step 2</h4><p>Let&#8217;s create a Policy model. This is where we store Amazon&#8217;s help &amp; customer service.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D-28!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D-28!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 424w, https://substackcdn.com/image/fetch/$s_!D-28!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 848w, https://substackcdn.com/image/fetch/$s_!D-28!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 1272w, https://substackcdn.com/image/fetch/$s_!D-28!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D-28!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png" width="1194" height="410" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:410,&quot;width&quot;:1194,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:85914,&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_!D-28!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 424w, https://substackcdn.com/image/fetch/$s_!D-28!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 848w, https://substackcdn.com/image/fetch/$s_!D-28!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 1272w, https://substackcdn.com/image/fetch/$s_!D-28!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F859d954d-1996-46eb-8631-0706d0b23be9_1194x410.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h4>Step 3</h4><p>We then update <code>seeds.rb</code> to save the policy pages of Amazon on the Policy model. The <code>seeds.rb</code> should look like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_H4X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_H4X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 424w, https://substackcdn.com/image/fetch/$s_!_H4X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 848w, https://substackcdn.com/image/fetch/$s_!_H4X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 1272w, https://substackcdn.com/image/fetch/$s_!_H4X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_H4X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png" width="1110" height="1004" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1004,&quot;width&quot;:1110,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:204250,&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_!_H4X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 424w, https://substackcdn.com/image/fetch/$s_!_H4X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 848w, https://substackcdn.com/image/fetch/$s_!_H4X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 1272w, https://substackcdn.com/image/fetch/$s_!_H4X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96a90d7d-a5b6-4804-8e26-b1a351300403_1110x1004.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h4>Step 4</h4><p>The next step is to install <code>langchainrb_rails</code></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HuxM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HuxM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 424w, https://substackcdn.com/image/fetch/$s_!HuxM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 848w, https://substackcdn.com/image/fetch/$s_!HuxM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 1272w, https://substackcdn.com/image/fetch/$s_!HuxM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HuxM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png" width="772" height="468" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:468,&quot;width&quot;:772,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:78499,&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_!HuxM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 424w, https://substackcdn.com/image/fetch/$s_!HuxM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 848w, https://substackcdn.com/image/fetch/$s_!HuxM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 1272w, https://substackcdn.com/image/fetch/$s_!HuxM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc0114b83-c689-4e57-b2b6-7ebeffa2162e_772x468.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h4>Step 5</h4><p>After install <code>langchainrb_rails</code> , the next step is to run the rails generator to add vectorsearch to the Policy model.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BHDC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BHDC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png 424w, https://substackcdn.com/image/fetch/$s_!BHDC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png 848w, https://substackcdn.com/image/fetch/$s_!BHDC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png 1272w, https://substackcdn.com/image/fetch/$s_!BHDC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BHDC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png" width="1456" height="444" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/213a8167-9102-4f34-a222-069ac75652a7_1464x446.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:444,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:94563,&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_!BHDC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png 424w, https://substackcdn.com/image/fetch/$s_!BHDC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png 848w, https://substackcdn.com/image/fetch/$s_!BHDC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.png 1272w, https://substackcdn.com/image/fetch/$s_!BHDC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F213a8167-9102-4f34-a222-069ac75652a7_1464x446.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><h4><br>Step 6</h4><p>The next step is to generate embeddings of the Policy model. In the console, do this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!052H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!052H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 424w, https://substackcdn.com/image/fetch/$s_!052H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 848w, https://substackcdn.com/image/fetch/$s_!052H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 1272w, https://substackcdn.com/image/fetch/$s_!052H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!052H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png" width="536" height="410" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:410,&quot;width&quot;:536,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69416,&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_!052H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 424w, https://substackcdn.com/image/fetch/$s_!052H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 848w, https://substackcdn.com/image/fetch/$s_!052H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 1272w, https://substackcdn.com/image/fetch/$s_!052H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2778c6c6-8e62-4e36-9204-420a617af82c_536x410.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h4>Step 7</h4><p>After embedding, the next step is to set up a connection to OpenAI's GPT-4 model using the Langchain library, configure a vector search mechanism, and then use this setup to process and respond to a question.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cqeI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cqeI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 424w, https://substackcdn.com/image/fetch/$s_!cqeI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 848w, https://substackcdn.com/image/fetch/$s_!cqeI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 1272w, https://substackcdn.com/image/fetch/$s_!cqeI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cqeI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png" width="1312" height="818" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:818,&quot;width&quot;:1312,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:168439,&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_!cqeI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 424w, https://substackcdn.com/image/fetch/$s_!cqeI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 848w, https://substackcdn.com/image/fetch/$s_!cqeI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 1272w, https://substackcdn.com/image/fetch/$s_!cqeI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9d6d886-dd42-4d6c-9144-9c22aa6f30fd_1312x818.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Step 8</h3><p>Now, it's time to test the chatbot in the terminal.</p><div id="youtube2-j-bcoFFQ45Q" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;j-bcoFFQ45Q&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/j-bcoFFQ45Q?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p>]]></content:encoded></item><item><title><![CDATA[Dynamic AI Prompts with PromptTemplates, Ruby, Langchain.rb and OpenAI]]></title><description><![CDATA[This tutorial talks about how to build a Ruby Chatbot with Langchain, PromptTemplate and OpenAI.]]></description><link>https://blog.ademartutor.com/p/dynamic-ai-prompts-with-prompttemplates</link><guid isPermaLink="false">https://blog.ademartutor.com/p/dynamic-ai-prompts-with-prompttemplates</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Sun, 14 Jan 2024 19:31:27 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/xQRpFtDctkE" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div id="youtube2-xQRpFtDctkE" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;xQRpFtDctkE&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/xQRpFtDctkE?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Previously, we've built a <a href="https://blog.ademartutor.com/p/hello-ai-world-with-ruby">basic terminal chatbot with Ruby</a>. Now, we are going to focus on PrompTemplates.</p><h3>What are PromptTemplates?&nbsp;</h3><p>PromptTemplates in Langchain.rb are game-changers. They allow you to create flexible, dynamic prompts with placeholders, which can be filled in with user input or other data at runtime. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.ademartutor.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 Building AI Apps for Startups with Ademar Tutor! 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>This adaptability is critical in prompt engineering, where the goal is to generate prompts that elicit the most accurate and relevant responses from an AI model.</p><p></p><h3>What is Prompt Engineering?</h3><p>Prompt engineering is the art of crafting prompts that guide AI models to provide the desired output. The way you phrase a prompt can significantly impact the model's response. </p><p>PromptTemplates offer a way to experiment with different phrasings and structures without hard-coding every possible prompt.</p><p></p><h3>Building an example chatbot</h3><p>Imagine building a chatbot that explains to preschools what specific profession and skills they need to succeed in that profession.</p><p></p><p><strong>Step 1</strong></p><p>Require the necessary libraries: OpenAI and Langchain.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aiZU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aiZU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 424w, https://substackcdn.com/image/fetch/$s_!aiZU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 848w, https://substackcdn.com/image/fetch/$s_!aiZU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 1272w, https://substackcdn.com/image/fetch/$s_!aiZU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aiZU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png" width="620" height="446" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:446,&quot;width&quot;:620,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:74372,&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_!aiZU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 424w, https://substackcdn.com/image/fetch/$s_!aiZU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 848w, https://substackcdn.com/image/fetch/$s_!aiZU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 1272w, https://substackcdn.com/image/fetch/$s_!aiZU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e22ed38-abbd-4fa8-83fe-2d702b0b4db0_620x446.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><strong>Step 2</strong></p><p>Set the logger level of Langchain to info, which means it will log informational messages. It is not a required step, but it's always good to know what's happening in the background with Langchain.rb</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vfoi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vfoi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 424w, https://substackcdn.com/image/fetch/$s_!Vfoi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 848w, https://substackcdn.com/image/fetch/$s_!Vfoi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 1272w, https://substackcdn.com/image/fetch/$s_!Vfoi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vfoi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png" width="806" height="410" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:410,&quot;width&quot;:806,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:75972,&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_!Vfoi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 424w, https://substackcdn.com/image/fetch/$s_!Vfoi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 848w, https://substackcdn.com/image/fetch/$s_!Vfoi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 1272w, https://substackcdn.com/image/fetch/$s_!Vfoi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F907f7ac3-6ffe-4234-a489-72987634bfb6_806x410.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><strong>Step 3</strong></p><p>Initialize a new <code>Langchain::LLM::OpenAI</code> object. This object is used to interact with OpenAI's API.</p><p>You need to provide your API key and other options.</p><p> <code>llm_options</code> is an empty hash here, but it can be used to pass additional options.</p><p><code>default_options</code> sets the default language model to GPT-4 for chat completions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8S3R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8S3R!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 424w, https://substackcdn.com/image/fetch/$s_!8S3R!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 848w, https://substackcdn.com/image/fetch/$s_!8S3R!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 1272w, https://substackcdn.com/image/fetch/$s_!8S3R!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8S3R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png" width="1456" height="447" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:447,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:147218,&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_!8S3R!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 424w, https://substackcdn.com/image/fetch/$s_!8S3R!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 848w, https://substackcdn.com/image/fetch/$s_!8S3R!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 1272w, https://substackcdn.com/image/fetch/$s_!8S3R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F460b76ed-83e1-470f-a0f8-6a553fc77bad_1818x558.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><strong>Step 4</strong></p><p>Create a new conversation object. This object will manage the conversation flow using the OpenAI model.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZV1v!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZV1v!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 424w, https://substackcdn.com/image/fetch/$s_!ZV1v!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 848w, https://substackcdn.com/image/fetch/$s_!ZV1v!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 1272w, https://substackcdn.com/image/fetch/$s_!ZV1v!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZV1v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png" width="1092" height="410" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:410,&quot;width&quot;:1092,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84964,&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_!ZV1v!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 424w, https://substackcdn.com/image/fetch/$s_!ZV1v!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 848w, https://substackcdn.com/image/fetch/$s_!ZV1v!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 1272w, https://substackcdn.com/image/fetch/$s_!ZV1v!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc7103bc-b511-41bf-a110-b6351fb26700_1092x410.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><strong>Step 5</strong></p><p>Create a new PromptTemplate object. This template has a placeholder `{profession}` that can be filled in. `input_variables` defines the placeholders expected in the template.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!igIK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!igIK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 424w, https://substackcdn.com/image/fetch/$s_!igIK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 848w, https://substackcdn.com/image/fetch/$s_!igIK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 1272w, https://substackcdn.com/image/fetch/$s_!igIK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!igIK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png" width="1456" height="397" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:397,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:134746,&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_!igIK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 424w, https://substackcdn.com/image/fetch/$s_!igIK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 848w, https://substackcdn.com/image/fetch/$s_!igIK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 1272w, https://substackcdn.com/image/fetch/$s_!igIK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff8b5859b-2f44-4528-aec1-323725dc082a_2048x558.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><strong>Step 6</strong></p><p>Prompt the user for the profession.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FKm3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FKm3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 424w, https://substackcdn.com/image/fetch/$s_!FKm3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 848w, https://substackcdn.com/image/fetch/$s_!FKm3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 1272w, https://substackcdn.com/image/fetch/$s_!FKm3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FKm3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png" width="890" height="446" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:446,&quot;width&quot;:890,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81457,&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_!FKm3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 424w, https://substackcdn.com/image/fetch/$s_!FKm3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 848w, https://substackcdn.com/image/fetch/$s_!FKm3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 1272w, https://substackcdn.com/image/fetch/$s_!FKm3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c2c0078-fdb8-497f-b61a-a9892ebb3dee_890x446.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p><strong>Step 7</strong></p><p>Format the prompt template with the user's input and send the message to the OpenAI model. The response from the model is then printed out.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Iu3j!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Iu3j!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 424w, https://substackcdn.com/image/fetch/$s_!Iu3j!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 848w, https://substackcdn.com/image/fetch/$s_!Iu3j!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 1272w, https://substackcdn.com/image/fetch/$s_!Iu3j!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Iu3j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png" width="1244" height="410" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:410,&quot;width&quot;:1244,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87751,&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_!Iu3j!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 424w, https://substackcdn.com/image/fetch/$s_!Iu3j!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 848w, https://substackcdn.com/image/fetch/$s_!Iu3j!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 1272w, https://substackcdn.com/image/fetch/$s_!Iu3j!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6445b2c9-25e5-48c6-a475-63ba866e354b_1244x410.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h5><strong>Full Code</strong></h5><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ey2M!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ey2M!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 424w, https://substackcdn.com/image/fetch/$s_!ey2M!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 848w, https://substackcdn.com/image/fetch/$s_!ey2M!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 1272w, https://substackcdn.com/image/fetch/$s_!ey2M!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ey2M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png" width="1456" height="873" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:873,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:262063,&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_!ey2M!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 424w, https://substackcdn.com/image/fetch/$s_!ey2M!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 848w, https://substackcdn.com/image/fetch/$s_!ey2M!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 1272w, https://substackcdn.com/image/fetch/$s_!ey2M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87954865-f368-4db3-a7d0-502c7e8bb279_2048x1228.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p>]]></content:encoded></item><item><title><![CDATA[Hello AI world with Ruby!]]></title><description><![CDATA[Building a small terminal-based chatbot app with OpenAI.]]></description><link>https://blog.ademartutor.com/p/hello-ai-world-with-ruby</link><guid isPermaLink="false">https://blog.ademartutor.com/p/hello-ai-world-with-ruby</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Fri, 12 Jan 2024 18:47:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/QhiKOhzuYr0" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div id="youtube2-QhiKOhzuYr0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;QhiKOhzuYr0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/QhiKOhzuYr0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>In this tutorial, we'll delve into creating your first AI-powered apps using Ruby, Langchain.rb library and OpenAI's GPTPT-4 API.&nbsp;</p><p><strong>Objective</strong></p><p>We'll create a terminal-based chatbot that allows you to OpenAI'S GPT-4. This chatbot will be able to process user inputs and generate relevant, context-aware responses.</p><p>1. First, we'll need to create a ruby file. Let's call this chat.rb</p><p>2. What we want to do next is import the necessary libraries</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fvwv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fvwv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 424w, https://substackcdn.com/image/fetch/$s_!fvwv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 848w, https://substackcdn.com/image/fetch/$s_!fvwv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 1272w, https://substackcdn.com/image/fetch/$s_!fvwv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fvwv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png" width="620" height="516" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/920d3685-ea93-4513-880d-7ee71fc26686_620x516.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:516,&quot;width&quot;:620,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83054,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fvwv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 424w, https://substackcdn.com/image/fetch/$s_!fvwv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 848w, https://substackcdn.com/image/fetch/$s_!fvwv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 1272w, https://substackcdn.com/image/fetch/$s_!fvwv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920d3685-ea93-4513-880d-7ee71fc26686_620x516.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><br></p><ul><li><p><strong>OpenAI</strong>: The openai library is a Ruby client for interacting with OpenAI's API.</p></li><li><p><strong>Langchain</strong>: Langchain is a Ruby library designed for building language applications.&nbsp;</p></li><li><p><strong>reline</strong>: Reline is a Ruby library used for readline-compatible input in command-line applications.</p></li></ul><p>3. Create an instance of `Langchain::LLM::OpenAI`. This class is a wrapper around OpenAI's API, specifically tailored for language models (LLMs).&nbsp;</p><p><strong>Side Note:</strong>&nbsp;The great thing with Langchain.rb is it supports other models, too, offering flexibility to switch between different AI models based on requirements.</p><p>4. Chat Interaction</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Emt3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Emt3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 424w, https://substackcdn.com/image/fetch/$s_!Emt3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 848w, https://substackcdn.com/image/fetch/$s_!Emt3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 1272w, https://substackcdn.com/image/fetch/$s_!Emt3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Emt3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png" width="1456" height="1102" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1102,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:368451,&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_!Emt3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 424w, https://substackcdn.com/image/fetch/$s_!Emt3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 848w, https://substackcdn.com/image/fetch/$s_!Emt3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 1272w, https://substackcdn.com/image/fetch/$s_!Emt3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbfce3f6-2068-4285-8d8c-164fd7ff22ea_1818x1376.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The method `prompt_for_message`, handles multiline user inputs and implements commands for ending the input or exiting the program. The commands are: "done", "end", "eof", and "exit"</p><p>5. Interactive Loop</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uCfI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uCfI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 424w, https://substackcdn.com/image/fetch/$s_!uCfI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 848w, https://substackcdn.com/image/fetch/$s_!uCfI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 1272w, https://substackcdn.com/image/fetch/$s_!uCfI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uCfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png" width="1456" height="846" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:846,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:253081,&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_!uCfI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 424w, https://substackcdn.com/image/fetch/$s_!uCfI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 848w, https://substackcdn.com/image/fetch/$s_!uCfI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 1272w, https://substackcdn.com/image/fetch/$s_!uCfI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F300567ff-7c18-4e06-97ec-e1baaf0ec1f7_2048x1190.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>The code continuously fetches user messages and uses `chat.message` to obtain and display responses from the AI, creating a dynamic conversation flow.</p><h3>Full code of chatbot.rb</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RrV5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RrV5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 424w, https://substackcdn.com/image/fetch/$s_!RrV5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 848w, https://substackcdn.com/image/fetch/$s_!RrV5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 1272w, https://substackcdn.com/image/fetch/$s_!RrV5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RrV5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png" width="1456" height="1837" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1837,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:481277,&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_!RrV5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 424w, https://substackcdn.com/image/fetch/$s_!RrV5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 848w, https://substackcdn.com/image/fetch/$s_!RrV5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 1272w, https://substackcdn.com/image/fetch/$s_!RrV5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8836b666-f5f4-40b8-ae94-6c6cae692f1f_1918x2420.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p>]]></content:encoded></item><item><title><![CDATA[Understanding Big-O Notation with Ruby]]></title><description><![CDATA[If the whole Big-O notation thing baffled you in college, guess what? You're in great company! &#128517; Many of us had our share of head-scratching moments.]]></description><link>https://blog.ademartutor.com/p/understanding-big-o-notation-with</link><guid isPermaLink="false">https://blog.ademartutor.com/p/understanding-big-o-notation-with</guid><dc:creator><![CDATA[Ademar Tutor]]></dc:creator><pubDate>Mon, 08 Jan 2024 09:19:30 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/10a0aa4f-6b05-4974-adba-45056bae8cd1_1456x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Big-O Notation in Ruby</h1><p>In college, Big-O Notations was taught in one of our courses. I really could not connect the dots back then. Big-O notations felt too theoretical at that time.</p><p>So, as a professional developer, I relied upon performance tools like&nbsp;<a href="https://github.com/MiniProfiler/rack-mini-profiler">rack-mini-profiler</a>,&nbsp;<a href="https://github.com/ruby/benchmark">Benchmark</a>,&nbsp;<a href="https://github.com/flyerhzm/bullet">bullet</a>, etc. </p><p>When 3rd party monitoring apps like&nbsp;<a href="https://www.appsignal.com/">AppSignal</a>&nbsp;and&nbsp;<a href="https://newrelic.com/">New Relic</a>&nbsp;started becoming good at monitoring performance, I began creating rules when writing code to avoid performance issues later when my code hits production.</p><h2>These are some of my "performance" rules:</h2><h4><strong>1. Be Mindful with Loops</strong></h4><p><strong>Rule:</strong>&nbsp;Reduce database hits inside loops.</p><pre><code># Bad
User.all.each do |user|
&nbsp;&nbsp;user.update_attribute(:status, "active")
end

# Good
User.update_all(status: "active")</code></pre><h4><strong>2. Optimize Database Queries</strong></h4><p><strong>Rule:</strong> Avoid N+1 queries by eager loading associated records.</p><pre><code># Bad
User.all.each do |user|
&nbsp;&nbsp;puts user.profile.name
end

# Good
User.includes(:profile).each do |user|
&nbsp;&nbsp;puts user.profile.name
end</code></pre><p>Note: Although, if you use the&nbsp;<a href="https://youtu.be/ktZLpjCanvg?t=242">Russian Doll Caching strategy</a>, this might not apply.</p><h4><strong>3. Background Jobs for Time-Consuming Tasks</strong></h4><p><strong>Rule</strong>: If all else fails, move long-running tasks to background jobs. Pray that the user does not need the data ASAP &#128591;</p><pre><code># Using Sidekiq or similar
LongTaskWorker.perform_async(user_id)</code></pre><p>I have realized you can get by with your app's performance by learning those simple rules. </p><p>However, having a solid foundation in your bag that has been used since 1894 might be a good idea.</p><h2>What is Big-O notation?</h2><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xOdJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xOdJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 424w, https://substackcdn.com/image/fetch/$s_!xOdJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 848w, https://substackcdn.com/image/fetch/$s_!xOdJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 1272w, https://substackcdn.com/image/fetch/$s_!xOdJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xOdJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png" width="392" height="203.87939698492463" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:414,&quot;width&quot;:796,&quot;resizeWidth&quot;:392,&quot;bytes&quot;:54650,&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_!xOdJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 424w, https://substackcdn.com/image/fetch/$s_!xOdJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 848w, https://substackcdn.com/image/fetch/$s_!xOdJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 1272w, https://substackcdn.com/image/fetch/$s_!xOdJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0ac4dee8-9eff-4a17-8bc2-f46cda854084_796x414.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>In plain words, Big-O notation describes the&nbsp;<strong>performance</strong>&nbsp;of your code using algebraic terms.&nbsp;<strong>Performance</strong>&nbsp;in this context refers to either the speed of execution or the amount of RAM the code consumes. </p><p>In computer science, these concepts are more formally known as 'time complexity' for speed and 'space complexity' for RAM usage. Big-O notation is used for both, but we're going to focus on speed here to simplify our discussion.</p><h2>Big-O in real-life</h2><p>In a web application, handling a process that involves sorting or searching through 100 data entries will naturally be slower compared to dealing with just 10 entries. </p><p><strong>The key question is:</strong> how much slower is it? Does the time taken increase 10x, a 100x, or perhaps even a 1000x?</p><p>This variance in processing speed might not be evident when dealing with smaller data sets. </p><p>However, the situation changes if your application's performance degrades significantly with the addition of each new entry in the database. </p><p>Such a decline in speed becomes a major concern, particularly as the volume of data grows larger in the app.</p><p>Understanding Big O notation is crucial in this context. It helps developers predict how their code will scale as data volumes increase, allowing them to choose the most efficient algorithms and data structures. </p><p>By anticipating performance issues before they occur, developers can optimize their applications for speed and efficiency, ensuring a smoother user experience even as data grows. This foresight is invaluable in maintaining a high-performing web application over time.</p><p></p><div><hr></div><p></p><p>Here's a super accurate emoji-based representation of Big-O notations to give you an idea of how fast they are as your data scales:</p><ul><li><p><strong>&#128640; O(1)</strong> - Speed does not depend on the scale of the dataset</p></li><li><p><strong>&#128644; O(log n)</strong> - If you have ten times more data, it only takes twice as long to process.</p></li><li><p><strong>&#128663; O(n)</strong> - If the amount of data increases tenfold, the processing time also increases tenfold.</p></li><li><p><strong>&#128690; O(n log n)</strong> - If you increase the data by ten times, the processing time will roughly increase by twenty times.</p></li><li><p><strong>&#127939;&#8205;&#9794;&#65039; O(n^2)</strong> - If the amount of data is multiplied by ten, the processing time increases by a factor of one hundred.&nbsp;</p></li><li><p><strong>&#128694;&#8205;&#9794;&#65039; O(2^n)</strong>- Doubling the amount of data leads to an exponential increase in processing time, making it significantly longer.</p></li></ul><h1>Big-O Notations In-depth</h1><h3><strong>&#128640; O(1)</strong></h3><p>O(1) indicates that the execution time of an operation remains constant, regardless of the size of the data set.</p><p>Example of accessing an element in a hash; the time taken is independent of the hash's size:</p><pre><code># Access time remains 
# constant for these

hash_with_100_items[:a]
hash_with_1000_items[:a]
hash_with_10000_items[:a]</code></pre><p>As a result, hashes generally perform better than arrays for large datasets. Here's another Ruby example:</p><pre><code># Retrieving an item 
# from arrays of varying 
# sizes

array_with_100_items[50]
array_with_1000_items[50]
array_with_10000_items[50]</code></pre><p>In this case, fetching an element at a specific index (like the 50th position) takes the same amount of time, regardless of the array's size.</p><h3><strong>&#128644; O(log n)</strong></h3><p>O(log n) describes an algorithm where the time it takes to complete a task increases logarithmically in relation to the size of the dataset. </p><p>This means that each time the dataset doubles in size, the number of steps required increases by a relatively small, fixed amount. </p><p>O(log n) operations are efficient and much faster than linear time operations for large datasets.</p><p>Here is a Ruby example illustrating O(log n) complexity:</p><p><strong>Binary Search:</strong></p><p>A binary search algorithm in a sorted array is a classic example of O(log n) complexity. At each step, it divides the dataset in half, significantly reducing the number of elements to search through.</p><p>Here&#8217;s an example of a Ruby code of binary search. We compare the time difference with <a href="https://github.com/ruby/benchmark">benchmark</a> when we double the dataset. <br><br>Code:</p><pre><code>require 'benchmark'

def binary_search(array, key)
  low = 0
  high = array.length - 1

  # This loop runs as long 
  # as the 'low' index is 
  # less than or equal to  
  # the 'high' index
  while low &lt;= high
    # Find the middle 
    # index of the 
    # current range
    mid = (low + high) / 2
    value = array[mid]

    # If the value is less 
    # than the key, narrow 
    # the search to the 
    # upper half of the 
    # array
    if value &lt; key
      low = mid + 1
    # If the value is 
    # greater than the 
    # key, narrow the 
    # search to the 
    # lower half of 
    # the array
    elsif value &gt; key
      high = mid - 1
    # If the key is found, 
    # return its index
    else
      return mid
    end
  end

  # If the key is not 
  # found in the 
  # array, return nil
  nil
end

# Example usage with an 
# array of 100 million 
# elements
array = (1..100000000).to_a
puts Benchmark.measure {
  binary_search(array, 30)
}

# Example usage with an 
# array of 200 million 
# elements
array = (1..200000000).to_a
puts Benchmark.measure {
  binary_search(array, 30)
}

# Example usage with an 
# array of 300 million 
# elements
array = (1..300000000).to_a
puts Benchmark.measure {
  binary_search(array, 30)
}</code></pre><p></p><h6><em>In this code, the binary search algorithm has a time complexity of O(log n) because it divides the search interval in half with each step. </em></h6><h6><em>In each iteration of the while loop, it either finds the element or halves the number of elements to check. </em></h6><h6><em>This halving process continues until the element is found or the interval is empty. </em></h6><h6><em>As a result, the time to complete the search increases logarithmically with the size of the array (</em><code>n</code><em>), making binary search efficient for large datasets.</em></h6><p></p><p>Result:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NXO1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NXO1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!NXO1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!NXO1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!NXO1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NXO1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png" width="690" height="167" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:690,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22027,&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_!NXO1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!NXO1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!NXO1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!NXO1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47c8a24f-fe23-48d3-a751-1e9a83d9e2aa_690x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Even got faster on with 300 million elements &#128517;</figcaption></figure></div><p></p><h3><strong>&#128663; O(n)</strong> </h3><p>O(n) describes the time complexity of an algorithm where the time to complete a task grows linearly and in direct proportion to the size of the input data set. This means that if you double the number of elements in your data set, the algorithm will take twice as long to complete.</p><p>Here is a Ruby example illustrating O(n) complexity:</p><p><strong>Summing all elements in an array:</strong></p><p>In this example, the time to sum all elements increases linearly with the number of elements in the array.</p><p>Code:</p><pre><code>require 'benchmark'

def sum_array(array)
  sum = 0
  # Iterating over each 
  # element in the array
  array.each do |element|
    # Adding each element 
    # to the sum
    sum += element  
  end
  # Returning the 
  # total sum
  sum  
end

# Summing an array of 
# 100 million elements
array = (1..100000000).to_a
puts Benchmark.measure {
  # The time taken here is 
  # proportional to the 
  # array's size
  sum_array(array)  
}

# Summing an array of 
# 200 million elements
array = (1..200000000).to_a
puts Benchmark.measure {
  # Time taken will be roughly 
  # twice that of the 100 
  # million array
  sum_array(array)  
}

# Summing an array of 
# 300 million elements
array = (1..300000000).to_a
puts Benchmark.measure {
  # Time taken will be roughly 
  # three times that of the 
  # 100 million array
  sum_array(array)  
}</code></pre><h6><em>In this code, the </em><code>sum_array</code><em> function has an O(n) complexity because it involves a single loop that iterates over each element of the array exactly once. </em></h6><h6><em>The time taken to execute this function scales linearly with the number of elements in the array (</em><code>n</code><em>). </em></h6><h6><em>Therefore, if you double the size of the array, the time to sum the array also doubles, which is characteristic of linear time complexity.</em></h6><p>Result:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t-KT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t-KT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!t-KT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!t-KT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!t-KT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t-KT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png" width="690" height="167" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:690,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23994,&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_!t-KT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!t-KT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!t-KT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!t-KT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcccb6a43-b4e7-4a95-8929-52944e4c4227_690x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Observe how the execution time scales linearly as we add 100 million more elements each time.</figcaption></figure></div><h3><strong>&#128690; O(n log n)</strong></h3><p>O(n log n) describes the time complexity of an algorithm where the time to complete a task increases at a rate proportional to the number of elements in the data set (n) multiplied by the logarithm of the number of elements (log n).</p><p>Here is a Ruby example illustrating O(n log n) complexity:</p><p><strong>Merge Sort:</strong> </p><p>Merge Sort is a classic example of an algorithm with O(n log n) complexity. It divides the array into halves, sorts each half, and then merges them back together.</p><p>Code:</p><pre><code>require 'benchmark'

def merge_sort(array)
  # Base case: a single 
  # element is already 
  # sorted
  if array.length &lt;= 1
    array
  else
    # Find the middle 
    # of the array
    mid = array.length / 2

    # Recursively sort 
    # the left half
    left = merge_sort(array[0...mid])
    # Recursively sort 
    # the right half
    right = merge_sort(array[mid..-1])

    # Merge the two 
    # sorted halves
    merge(left, right)
  end
end

def merge(left, right)
  sorted = []
  # Until one of the arrays 
  # is empty,pick the smaller 
  # element from the front 
  # of each array
  until left.empty? || right.empty?
    if left.first &lt;= right.first
      sorted &lt;&lt; left.shift
    else
      sorted &lt;&lt; right.shift
    end
  end

  # Concatenate the remaining 
  # elements (one of the arrays 
  # may have elements left)
  sorted.concat(left).concat(right)
end


# Benchmarking with 
# 10 million elements
array = (1..10000000).to_a
puts Benchmark.measure {
  merge_sort(array)
}

# Benchmarking with 
# 20 million elements
array = (1..20000000).to_a
puts Benchmark.measure {
  merge_sort(array)
}

# Benchmarking with 
# 30 million elements
array = (1..30000000).to_a
puts Benchmark.measure {
  merge_sort(array)
}
</code></pre><h6><em>The </em><code>merge_sort</code><em> function exhibits O(n log n) complexity because it involves a divide-and-conquer approach. </em></h6><h6><em>The array is repeatedly divided into halves (resulting in a logarithmic number of divisions, i.e., log n), and each half is sorted and then merged. </em></h6><h6><em>The merging process for each level is linear in the size of the input (i.e., n), leading to a total time complexity of O(n log n). </em></h6><h6><em>This makes merge sort much more efficient for large datasets compared to algorithms with quadratic time complexities (like bubble sort or insertion sort), especially as the size of the data increases.</em></h6><p></p><p>Result:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jVH9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jVH9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!jVH9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!jVH9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!jVH9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jVH9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png" width="690" height="167" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:690,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24746,&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_!jVH9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!jVH9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!jVH9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!jVH9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a25162b-c55d-44ad-bc0e-f4b9cbd8c98e_690x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The <em>slowness</em>  of execution time of merge sort handling millions of elements becomes really obvious.</figcaption></figure></div><p></p><p></p><h3><strong>&#127939;&#8205;&#9794;&#65039; O(n^2)</strong></h3><p>O(n^2) describes the time complexity of an algorithm where the time to complete a task is proportional to the square of the number of elements in the input dataset. This means that if the number of elements doubles, the time to complete the task increases by four times. Algorithms with O(n^2) complexity are generally less efficient for large datasets compared to O(n log n) or O(n) algorithms.</p><p>Here is a Ruby example illustrating O(n^2) complexity.</p><p><strong>Bubble Sort:</strong> </p><p>Bubble Sort is a simple sorting algorithm that repeatedly steps through the list, compares adjacent elements, and swaps them if they are in the wrong order. The pass through the list is repeated until the list is sorted.</p><p>Code:</p><pre><code>require 'benchmark'

def bubble_sort(array)
  n = array.length
  # Loop until no more swaps are needed
  loop do
    swapped = false
    # Iterate through the array. The '-1' is because Ruby arrays are zero-indexed,
    # and we're comparing each element with the next.
    (n-1).times do |i|
      # Compare adjacent elements
      if array[i] &gt; array[i+1]
        # Swap if they are in the wrong order
        array[i], array[i+1] = array[i+1], array[i]
        # Indicate a swap occurred
        swapped = true
      end
    end
    # Break the loop if no swaps occurred in the last pass
    break unless swapped
  end
  # Return the sorted array
  array
end

# Benchmarking with 10,000 elements
array = (1..10000).to_a.shuffle
puts Benchmark.measure {
  bubble_sort(array)
}

# Benchmarking with 20,000 elements
array = (1..20000).to_a.shuffle
puts Benchmark.measure {
  bubble_sort(array)
}

# Benchmarking with 30,000 elements
array = (1..30000).to_a.shuffle
puts Benchmark.measure {
  bubble_sort(array)
}
</code></pre><h6><em>In this </em><code>bubble_sort</code><em> method, the O(n^2) complexity arises from the nested loop structure:</em></h6><h6><em>  a) The </em><code>loop</code><em> construct potentially iterates </em><code>n</code><em> times (in the worst case where the array is in reverse order).</em></h6><h6><em>  b) Inside this loop, there's a </em><code>(n-1).times</code><em> loop that also iterates up to </em><code>n-1</code><em> times for each outer loop iteration.</em></h6><h6><em>This nesting of loops, where each loop can run 'n' times, leads to the time complexity of O(n^2).</em></h6><p></p><p>Result:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ipZz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ipZz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!ipZz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!ipZz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!ipZz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ipZz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png" width="690" height="167" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:690,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24555,&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_!ipZz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!ipZz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!ipZz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!ipZz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3184d117-04ee-407e-830a-2f7f75df1e73_690x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Noticed that I just maxed out the elements to 30,000. It was pretty slow already &#128517;</figcaption></figure></div><p></p><h3>&#128694;&#8205;&#9794;&#65039; O(2^n)</h3><p>O(2^n) describes the time complexity of an algorithm where the time to complete a task doubles with each additional element in the input data set. This kind of complexity is typical in algorithms that involve recursive solutions to problems where the solution involves creating two or more subproblems for each problem. Such algorithms are often seen as inefficient for large datasets due to their exponential time growth.</p><p>Here is a Ruby example illustrating O(2^n) complexity.</p><p><strong>Fibonacci Sequence (Recursive Implementation):</strong></p><p>A classic example of O(2^n) complexity is the recursive calculation of the Fibonacci sequence, where each number is the sum of the two preceding ones.<br><br>Code:</p><pre><code>require 'benchmark'

def fibonacci(n)
  return n if n &lt;= 1
  fibonacci(n - 1) + fibonacci(n - 2)
end

puts Benchmark.measure {
  fibonacci(10)
}

puts Benchmark.measure {
  fibonacci(20)
}

puts Benchmark.measure {
  fibonacci(30)
}</code></pre><h6><em>The number of operations grows exponentially with the input size, characteristic of O(2^n) time complexity. This exponential growth makes these algorithms impractical for large input sizes due to the rapid increase in computation time.</em></h6><p>Result:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MkoQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MkoQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!MkoQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!MkoQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!MkoQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MkoQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png" width="690" height="167" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:167,&quot;width&quot;:690,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21901,&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_!MkoQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 424w, https://substackcdn.com/image/fetch/$s_!MkoQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 848w, https://substackcdn.com/image/fetch/$s_!MkoQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 1272w, https://substackcdn.com/image/fetch/$s_!MkoQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a586dde-0fa1-45af-9c75-be01750beb34_690x167.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">I jdid not dare to use numbers above 100. It would be super slow &#128034;</figcaption></figure></div><p></p><h3><strong>Summary</strong></h3><p>You should not be using these code examples in production apps. There are built-in <a href="https://www.rubyguides.com/2017/07/ruby-sort/">Ruby sort</a> and search. And if you are sorting records (in PostgreSQL), please use the <a href="https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-order-by/">database feature</a>.</p><p>I hope you can appreciate Big-O notation and apply this to your daily work. &#128640;</p><p></p><div><hr></div><p></p><blockquote><p>Hello there!</p><p>Do you have a startup idea or an exciting project you&#8217;re passionate about? I&#8217;d love to bring your vision to&nbsp;life!</p><p>I&#8217;m a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React.</p><p>Whether you&#8217;re looking to innovate, grow your business, or bring a creative idea to the forefront, I&#8217;m here to provide tailored solutions that meet your unique&nbsp;needs.</p><p><a href="https://www.linkedin.com/in/ademar-tutor-0a95972a">Let&#8217;s collaborate to make something amazing!</a></p><p>Sincerely,<br>Ademar Tutor<br>hey@ademartutor.com</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.linkedin.com/in/ademar-tutor-0a95972a/&quot;,&quot;text&quot;:&quot;Let's work together!&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.linkedin.com/in/ademar-tutor-0a95972a/"><span>Let's work together!</span></a></p><p></p>]]></content:encoded></item></channel></rss>