<?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"><channel><title><![CDATA[pulbasso.dev]]></title><description><![CDATA[pulbasso.dev]]></description><link>https://pulbasso.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 06:12:56 GMT</lastBuildDate><atom:link href="https://pulbasso.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A First Landing, AI-Enhanced Coding & Small Wins 🚀]]></title><description><![CDATA[Hey folks!
It’s been a while since my last update — and the past month hasn’t been all about Fidely.Between studying for a project management course 📚 and other work commitments, time has been tight.
But I still managed to make progress on one cruci...]]></description><link>https://pulbasso.dev/a-first-landing-ai-enhanced-coding-and-small-wins</link><guid isPermaLink="true">https://pulbasso.dev/a-first-landing-ai-enhanced-coding-and-small-wins</guid><category><![CDATA[Build In Public]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[Netlify]]></category><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Sat, 05 Jul 2025 14:15:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1751724754555/610b9a0e-959c-4952-ae95-dc967c08d2e1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey folks!</p>
<p>It’s been a while since my last update — and the past month hasn’t been all about Fidely.<br />Between studying for a project management course 📚 and other work commitments, time has been tight.</p>
<p>But I still managed to make progress on one crucial piece: <strong>the first version of the Fidely landing page!</strong></p>
<hr />
<h2 id="heading-the-first-landing-page-is-live">The First Landing Page is Live!</h2>
<p>The landing is focused on <strong>shop owners</strong>, as they are my primary target customers.<br />It’s based on the mockup I shared last month, and I’m happy to finally have something concrete online:<br />👉 <a target="_blank" href="http://fidely.pulbasso.dev">fidely.pulbasso.dev</a></p>
<p>For the tech stack, I used:</p>
<ul>
<li><p><strong>Next.js</strong></p>
</li>
<li><p><strong>React</strong></p>
</li>
<li><p><strong>TailwindCSS</strong></p>
</li>
</ul>
<p>I deployed the landing on <strong>Netlify</strong>. Technically, it could be fully exported as a static site, but for now I decided to skip this step to keep things simple.</p>
<p>Is it perfect? Absolutely not.<br />But I strongly believe it’s <strong>way better to launch an imperfect first version</strong> and improve iteratively, rather than chase perfection and risk getting stuck.</p>
<hr />
<h2 id="heading-why-small-wins-matter">Why Small Wins Matter</h2>
<p>Even though Fidely is still small, it’s surprisingly complex:<br />So many moving parts, from the app logic to the business aspects.</p>
<p>With limited time available, I need <strong>incremental results</strong> to stay motivated and keep pursuing my goal.</p>
<p>Seeing the landing live, even in its raw form, gives me a sense of progress and something tangible to build upon.</p>
<hr />
<h2 id="heading-evolving-my-ai-workflow">🤖 Evolving My AI Workflow</h2>
<p>Lately, I’ve been integrating <strong>AI more and more into my development process</strong> — and I’m slowly finding my own balance.</p>
<p>A few personal thoughts:</p>
<ul>
<li><p><strong>“Vibe coding” with AI is dangerous</strong>:<br />  Sure, it gives you a quick solution, sometimes even working code. But it often hides key implementation details, which leads to a shallow understanding of your codebase.<br />  Without that deep knowledge, evolving your app later becomes a nightmare.</p>
</li>
<li><p><strong>Guided AI usage is key</strong>:<br />  Using AI purposefully, with focused prompts, while maintaining control over the architecture and code structure, has proven the most effective path for me.<br />  It dramatically speeds up development without sacrificing code quality or maintainability.</p>
</li>
<li><p><strong>AI for brainstorming</strong>:<br />  Having your codebase in context and using AI to discuss architecture or design choices is a game-changer. What used to take hours of solo research can now be condensed into a few minutes of collaborative ideation.</p>
</li>
</ul>
<p>Currently, my tools of choice are:</p>
<p>✅ <strong>Cursor + Claude</strong> for personal projects<br />✅ <strong>GitHub Copilot</strong> for work</p>
<hr />
<h2 id="heading-early-comparisons">Early Comparisons</h2>
<p>My initial impression?</p>
<ul>
<li><p>Cursor + Claude 3.5 feels <strong>ahead in quality and reasoning</strong>, especially on complex tasks.</p>
</li>
<li><p>GitHub Copilot with GPT-4o seems a bit behind, but I’ve used it less intensively, so the comparison may not be entirely fair.</p>
</li>
<li><p>In personal testing, I’ve noticed <strong>better answers from OpenAI’s GPT-4o on ChatGPT</strong> compared to the same model used via Copilot.</p>
</li>
</ul>
<p>For now, I find myself leaning heavily on Claude inside Cursor — but I’ll keep testing.</p>
<hr />
<p>That’s it for this month.<br />It may not have been the most productive period for Fidely, but even small steps like launching the landing keep the momentum alive.</p>
<p><strong>Stay loyal</strong> 😄</p>
]]></content:encoded></item><item><title><![CDATA[Fidely Update #5 — Market Research, Landing Page & Strategy Shaping 🚀]]></title><description><![CDATA[Back again with a new chapter in the Fidely journey.This time it's a bit less about code and a bit more about strategy, market research, and preparation for the next phase.
Market Research: not as simple as it sounds
With very limited time (as usual)...]]></description><link>https://pulbasso.dev/fidely-update-5-market-research-landing-page-and-strategy-shaping</link><guid isPermaLink="true">https://pulbasso.dev/fidely-update-5-market-research-landing-page-and-strategy-shaping</guid><category><![CDATA[Build In Public]]></category><category><![CDATA[SaaS]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Thu, 05 Jun 2025 10:20:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749117796864/4f799aa9-de65-4c2d-a810-086c43835a74.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back again with a new chapter in the Fidely journey.<br />This time it's a bit less about code and a bit more about <strong>strategy, market research, and preparation for the next phase</strong>.</p>
<h2 id="heading-market-research-not-as-simple-as-it-sounds">Market Research: not as simple as it sounds</h2>
<p>With very limited time (as usual), I’ve finally carved out some evenings to work on a <strong>proper market analysis</strong> for Fidely — with special focus on Italy and my initial target area: Liguria 🇮🇹.</p>
<p>Instead of just relying on random Google searches, I’ve tried to build something a bit more structured and robust:</p>
<ul>
<li><p>✅ Searched for reliable sources (official reports, studies, government data)</p>
</li>
<li><p>✅ Used <strong>Perplexity AI</strong> and <strong>OpenAI Deep Research</strong> to find resources I hadn't initially discovered</p>
</li>
<li><p>✅ Processed the data inside <strong>Google NotebookLM</strong> to organize, analyze and double-check sources to minimize hallucinations and mistakes</p>
</li>
</ul>
<p>The goal?<br />👉 Collect <strong>solid, validated data</strong> that I can use for future marketing material, landing pages, and potentially to test actual ads and demand.</p>
<h3 id="heading-some-quick-takeaways">🎯 Some quick takeaways</h3>
<ul>
<li><p>The Italian loyalty market is growing fast: estimated <strong>€3.5 billion in 2023</strong>, with 11–12% annual growth</p>
</li>
<li><p>Around <strong>1 million micro &amp; small businesses</strong> in Italy could be potential Fidely clients: shops, restaurants, salons, bars, etc.</p>
</li>
<li><p>In Liguria specifically (my initial focus), there are roughly <strong>10,000–15,000 micro B2C businesses</strong> with good adoption potential.</p>
</li>
<li><p>Despite these numbers, the <strong>digitalization level is still very low</strong>: only ~46% of Ligurian SMEs have basic digital skills</p>
</li>
<li><p>Consumers are fully mobile-first:</p>
<ul>
<li><p>WhatsApp usage: <strong>89% of Italians</strong></p>
</li>
<li><p>Mobile payments are exploding: +53% YoY in 2024</p>
</li>
<li><p>Digital loyalty apps (Stocard, Klarna, Apple Wallet) are now mainstream.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-why-fidely-might-fit-here">💡 Why Fidely might fit here</h3>
<ul>
<li><p>Many businesses still rely on <strong>manual loyalty cards</strong> or very fragmented tools.</p>
</li>
<li><p>Existing loyalty platforms often feel <strong>too complex, too expensive, or too generic</strong> for very small shops.</p>
</li>
<li><p>There's room for a <strong>"lightweight, easy-to-use, hyperlocal" SaaS</strong> focused on helping micro-businesses go digital — without scaring them with CRM jargon, big data dashboards or enterprise software.</p>
</li>
</ul>
<p>One of my favorite stats from this research:</p>
<blockquote>
<p><em>"Acquiring a new customer costs 5 to 25 times more than retaining an existing one."</em><br />(<a target="_blank" href="https://hbr.org/2014/10/the-value-of-keeping-the-right-customers">Harvard Business Review</a>)</p>
</blockquote>
<p>Exactly why loyalty programs can make a huge difference for small local businesses — and exactly why Fidely exists.</p>
<h2 id="heading-the-first-landing-page-mockup">The First Landing Page Mockup</h2>
<p>With the research done, I started designing the <strong>first version of the landing page</strong>.</p>
<blockquote>
<p>My direct clients are the shop owners, so the landing is fully targeted at them.</p>
</blockquote>
<p>I'm not a designer, but I tried to keep it minimal, focused, and clear about:</p>
<ul>
<li><p>The pain points (low return customers, high acquisition costs)</p>
</li>
<li><p>The solution (easy digital loyalty tools)</p>
</li>
<li><p>The local focus (Liguria first!)</p>
</li>
</ul>
<p>Here’s a preview of the mockup:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749117820262/6b17de8d-8aff-48f5-bc8f-6dd60586458a.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-landing-page-tech-stack">🎯 Landing Page Tech Stack</h2>
<p>Unlike the main Fidely app, the landing page will be its own <strong>separate project</strong> for better flexibility:</p>
<ul>
<li><p>✅ <strong>Next.js 14</strong></p>
</li>
<li><p>✅ <strong>TailwindCSS</strong></p>
</li>
<li><p>✅ Full static export possible → deployable on a CDN like Cloudflare.</p>
</li>
</ul>
<p>In the next days/weeks, I’ll start actually building the landing and running the first real-world market tests.</p>
<h2 id="heading-whats-next">What's Next?</h2>
<ul>
<li><p>🚀 Build &amp; deploy the landing page</p>
</li>
<li><p>📊 Start testing Italian ads to validate real demand</p>
</li>
<li><p>🤝 Prepare early onboarding for local shop owners</p>
</li>
<li><p>💻 Resume app development with:</p>
<ul>
<li><p>Reward redemption flow</p>
</li>
<li><p>Customer-facing app interface</p>
</li>
<li><p>More detailed analytics for business owners</p>
</li>
</ul>
</li>
</ul>
<p>That's it for now!<br />Slow evenings, but steady progress.</p>
<p><strong>Stay loyal</strong> 😄</p>
]]></content:encoded></item><item><title><![CDATA[How I added analytics and confetti to my loyalty app?]]></title><description><![CDATA[Hey folks!
Back again with another update on Fidely, the loyalty app I’ve been building in my spare time as part of The 10-Minute Company series. I’ve been making steady progress, and I’m super excited to share what’s new—because this time, there’s m...]]></description><link>https://pulbasso.dev/how-i-added-analytics-and-confetti-to-my-loyalty-app</link><guid isPermaLink="true">https://pulbasso.dev/how-i-added-analytics-and-confetti-to-my-loyalty-app</guid><category><![CDATA[Build In Public]]></category><category><![CDATA[Developer]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Mon, 05 May 2025 09:55:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746438607814/89ab4e2d-c23a-40ba-a629-6542c202d0ca.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p> Hey folks!</p>
<p>Back again with another update on <strong>Fidely</strong>, the loyalty app I’ve been building in my spare time as part of <em>The 10-Minute Company</em> series. I’ve been making steady progress, and I’m super excited to share what’s new—because this time, there’s more <em>polish</em>, more <em>insight</em>, and a better <em>experience</em>.</p>
<p>If this is your first time hearing about Fidely, check out the <a target="_blank" href="https://pul.hashnode.dev/1-fidely-loyalty-app-side-project">first post in the series</a> to catch up on what it’s all about.</p>
<hr />
<h2 id="heading-home-dashboard-gets-analytics">📊 Home Dashboard Gets Analytics</h2>
<p>One of the key selling points of Fidely is helping small business owners <strong>understand their customers</strong> better. To make this real, I’ve added a basic <strong>analytics section</strong> on the home dashboard.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746437147447/2c5c0315-35d7-4aa3-81e1-6db1486c009f.png" alt class="image--center mx-auto" /></p>
<p>This gives the shop owner some quick insights about:</p>
<ul>
<li>How many cards are active  </li>
<li>Which campaigns are running  </li>
<li>Key stats from recent activity  </li>
</ul>
<p>The current dashboard acts as a preview—eventually, these metrics will be expanded into a dedicated <strong>analytics section</strong> with proper filters, charts, and detailed views. But it’s a good first step!</p>
<hr />
<h2 id="heading-a-faster-operator-dashboard">⚡ A Faster Operator Dashboard</h2>
<p>Let’s talk about <strong>speed</strong>. The Operator Dashboard now feels snappier, smarter, and more helpful.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746437338600/de931ef0-9c6e-4498-8ca6-36398fb5a410.png" alt class="image--center mx-auto" /></p>
<p>The new flow is designed for real-world usage:<br />Operators are often juggling customers, so every click matters.</p>
<p>Here’s how it works:</p>
<ul>
<li>Search for a card quickly  </li>
<li>Get instant results under the search bar  </li>
<li><p>If there’s a single match, the app auto-selects the card and shows this view:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746437573283/8da8011f-79c1-44cf-b1df-dbf9a9d0450b.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p>From here the operator can:</p>
<p>✅ View card details<br />✅ Join a campaign if the card hasn’t yet<br />✅ Assign points/stamps immediately<br />✅ See campaign progress  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746437740973/b740fb8c-a288-4b48-ac95-98c88921c567.png" alt class="image--center mx-auto" /></p>
<p>Once points are added, the app brings the operator back to the search view—so they can help the next customer quickly.</p>
<p>But wait—there’s more!</p>
<p>If the customer <strong>unlocks a reward</strong>, the app throws a <strong>confetti animation</strong> (yes, for real 😄), and the workflow pauses, giving the operator time to ask if the customer wants to redeem it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746437881955/981aa844-06aa-4515-889e-b494a95f4c6b.png" alt class="image--center mx-auto" /></p>
<p>It’s small stuff, but it matters for <strong>UX and flow</strong>.</p>
<hr />
<h2 id="heading-bug-fixing-time">🐛 Bug Fixing Time</h2>
<p>I also spent time cleaning up annoying bugs that were dragging the user experience down.</p>
<p>From navigation glitches to weird reloads—many small fixes that, together, make the app feel smoother and more consistent.</p>
<hr />
<h2 id="heading-a-new-card-layout">💳 A New Card Layout</h2>
<p>Inspired by credit cards, I gave the <strong>customer card UI</strong> a little makeover.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746437943682/5ff51f7d-4a4c-447f-9d91-b05589a5d012.png" alt class="image--center mx-auto" /></p>
<p>Not sure if this will be the final look, but it’s a fun experiment—and it makes cards feel more "real".</p>
<hr />
<h2 id="heading-global-notification-system">🔔 Global Notification System</h2>
<p>Last but not least: I’ve added a <strong>toast notification system</strong>.<br />Whenever a user takes an action—like assigning points, joining a campaign, or redeeming a reward—they’ll now get <strong>instant visual feedback</strong>.</p>
<p>It’s a small feature, but it adds a lot of clarity.</p>
<hr />
<h2 id="heading-whats-next">What’s Next?</h2>
<ul>
<li>More detailed analytics  </li>
<li>Campaign creation wizard  </li>
<li>Customer view and reward redemption flow  </li>
<li>Localization (yes, Fidely is still mostly in Italian 😅)</li>
</ul>
<hr />
<p>That’s it for now. As always, I’m building Fidely a few evenings at a time—progress is slow but steady.<br />If you're working on a microSaaS or playing around with loyalty mechanics, I’d love to hear from you!</p>
<p>Let’s keep building!</p>
]]></content:encoded></item><item><title><![CDATA[#3 Fidely Project Update: a better UI 💪]]></title><description><![CDATA[Time for a long-overdue update on the Fidely Project!Yeah, this post took a while to come out—writing consistently is still a challenge for me. But hey, I'm trying to stay on track and keep this blog alive for the months ahead.
In this post, I’ll wal...]]></description><link>https://pulbasso.dev/3-fidely-project-update-a-better-ui</link><guid isPermaLink="true">https://pulbasso.dev/3-fidely-project-update-a-better-ui</guid><category><![CDATA[Build In Public]]></category><category><![CDATA[React]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[DrizzleORM]]></category><category><![CDATA[SaaS]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Mon, 24 Mar 2025 23:00:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742857023279/df07c20b-bc64-4bec-94b3-4b4506ff6f20.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Time for a long-overdue update on the <strong>Fidely Project</strong>!<br />Yeah, this post took a while to come out—writing consistently is still a challenge for me. But hey, I'm trying to stay on track and keep this blog alive for the months ahead.</p>
<p>In this post, I’ll walk you through what I’ve been building lately. Lots of progress, especially on the <strong>frontend</strong>, but also a good amount of refactoring under the hood.</p>
<p>If this is your first time hearing about Fidely, I recommend <a target="_blank" href="https://pulbasso.dev/series/the-10-minute-company">checking out the series</a> to understand the context and the problem I'm trying to solve.</p>
<hr />
<h2 id="heading-whats-new">What's New?</h2>
<p>Right now, I’m mostly focused on the <strong>shop owner</strong>’s point of view.</p>
<p>Here’s what a shop owner can now do:</p>
<p>✅ Register/Login<br />✅ Create and manage one or more companies<br />✅ Set up loyalty campaigns (both points collection and stamps)<br />✅ Create customer cards<br />✅ Assign points or stamps to customer cards from the <strong>Operator View</strong><br />✅ View and manage their user profile</p>
<blockquote>
<p>All features are working in the app already — still mostly in Italian, but internationalization is on my radar for the next releases!</p>
</blockquote>
<hr />
<h3 id="heading-login-amp-register">🔐 Login &amp; Register</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742854291211/a7636850-bd80-456a-b478-757187e27713.png" alt class="image--center mx-auto" /></p>
<p>Straightforward login and signup flow. Nothing fancy, but it works!</p>
<hr />
<h3 id="heading-home-dashboard">🏠 Home Dashboard</h3>
<p>The app now includes a sidebar with different sections (some are still under construction).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742854618659/2506f03e-f336-4f40-927f-8155cc6ad27a.png" alt class="image--center mx-auto" /></p>
<p>Let’s break it down:</p>
<ul>
<li><p><strong>Company Switcher</strong> at the top: if the user manages multiple companies, this dropdown lets them switch between them or create a new one.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742855089146/3139da10-3183-482f-8f23-d3526e020ab4.png" alt class="image--center mx-auto" /></p>
</li>
<li><p><strong>Operatività</strong>: this section is all about speed. It’s designed for quick actions like:</p>
<ul>
<li><p>Viewing recent transactions</p>
</li>
<li><p>Creating a new customer card</p>
</li>
<li><p>Launching the operator interface for assigning points/stamps</p>
</li>
</ul>
</li>
</ul>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742855145142/546e61d7-7702-4fdd-9da4-a0a47d59c9c1.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p><strong>Attività / Campagne / Carte</strong>: classic CRUD sections where shop owners can edit their business info, loyalty campaigns, and customer cards.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742855437903/e47c0473-19ed-4978-876b-6eef282cc0b3.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<hr />
<h2 id="heading-wizard-engine">Wizard Engine</h2>
<p>One of the coolest things I’ve added recently is a <strong>custom wizard engine</strong>.</p>
<p>I noticed that multiple flows in the app follow a “step-by-step” pattern—like onboarding, campaign setup, card creation, and more.</p>
<p>So instead of repeating the same logic all over, I built a tiny <strong>abstract wizard engine</strong>. It handles step navigation and state management, so I can reuse it for any future wizard.</p>
<p>First implementation? The card creation flow:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742856169492/7fe93a09-8253-48da-a24d-a83c08df8fd4.png" alt class="image--center mx-auto" /></p>
<p>It’s basic but working! And adding new wizards should now take a fraction of the time.</p>
<hr />
<h2 id="heading-whats-next">What's Next?</h2>
<p>In the upcoming evenings and weekends (aka my dev time), I’ll be working on:</p>
<p>🔧 Completing more wizards (e.g., for campaign creation)<br />🪲 Fixing annoying bugs<br />🛠 Starting to polish the operator flow and customer-side logic<br />🌍 Adding support for multiple languages</p>
<hr />
<p>That’s all for now! If you're building something similar or have questions about my tech stack or structure, let’s chat!</p>
<p>I'll keep you posted.<br />Until next time—stay loyal 😄</p>
]]></content:encoded></item><item><title><![CDATA[#5 Daily Rabbit Holes: Rust Threads + TUI = A Nerdy Little CPU Monitor]]></title><description><![CDATA[Welcome back to another article of The Daily Rabbit Hole.
Today’s rabbit hole starts with a simple question:

"How to build a basic CPU monitor using Rust and a terminal UI?"

The real goal here is to create a simple and visual example to practice us...]]></description><link>https://pulbasso.dev/5-daily-rabbit-holes-rust-threads-tui-a-nerdy-little-cpu-monitor</link><guid isPermaLink="true">https://pulbasso.dev/5-daily-rabbit-holes-rust-threads-tui-a-nerdy-little-cpu-monitor</guid><category><![CDATA[Rust]]></category><category><![CDATA[TUI]]></category><category><![CDATA[terminal]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Sun, 23 Mar 2025 18:56:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742755882373/492184dd-d3a9-4578-9654-62aeed6cfc33.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome back to another article of <em>The Daily Rabbit Hole.</em></p>
<p>Today’s rabbit hole starts with a simple question:</p>
<blockquote>
<p><em>"How to build a basic CPU monitor using Rust and a terminal UI?"</em></p>
</blockquote>
<p>The real goal here is to create a simple and visual example to practice using threads in Rust. It’s a small playground to explore shared memory, concurrency, and synchronization.</p>
<p>For this little project we will use the following:</p>
<ul>
<li><p><a target="_blank" href="https://github.com/gyscos/cursive"><strong>Cursive</strong></a>: a powerful TUI (Text-based UI) library in Rust</p>
</li>
<li><p><a target="_blank" href="https://docs.rs/sysinfo/latest/sysinfo/"><strong>sysinfo</strong></a>: a system stats collector</p>
</li>
<li><p><a target="_blank" href="https://doc.rust-lang.org/book/ch16-01-threads.html"><code>Threads</code> + <code>Arc&lt;Mutex&lt;T&gt;&gt;</code> for safe shared state</a></p>
</li>
</ul>
<h2 id="heading-project-setup">Project Setup</h2>
<p>Create a Cargo project, add the Cursive and Sysinfo dependency…</p>
<pre><code class="lang-bash">cargo new threads-cursive-sysinfo-example
<span class="hljs-built_in">cd</span> threads-cursive-sysinfo-example
cargo add cursive
cargo add sysinfo
</code></pre>
<h2 id="heading-the-code">The Code</h2>
<pre><code class="lang-rust"><span class="hljs-comment">// main.rs</span>
<span class="hljs-keyword">use</span> std::{sync::{Arc, Mutex}, thread, time::Duration};

<span class="hljs-keyword">use</span> cursive::{
    view::Nameable,
    views::{LinearLayout, TextView, Panel, DummyView},
    Cursive, CursiveExt,
    theme::{Theme, ColorStyle, PaletteColor, Color},
    align::HAlign,
};
<span class="hljs-keyword">use</span> sysinfo::System;

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AppState</span></span> {
  system: Mutex&lt;System&gt;,
  usage_data: Mutex&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">f32</span>&gt;&gt;
}

<span class="hljs-keyword">impl</span> AppState {
  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">new</span></span>() -&gt; Arc&lt;<span class="hljs-keyword">Self</span>&gt;{
    <span class="hljs-keyword">let</span> sys = System::new_all();
    <span class="hljs-keyword">let</span> core_count = sys.cpus().len();
    Arc::new(<span class="hljs-keyword">Self</span> {
      system: Mutex::new(sys),
      usage_data: Mutex::new(<span class="hljs-built_in">vec!</span>[<span class="hljs-number">0.0</span>; core_count])
    })
  }

  <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">refresh_cpu_usage</span></span>(&amp;<span class="hljs-keyword">self</span>) {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> sys = <span class="hljs-keyword">self</span>.system.lock().unwrap();
    sys.refresh_cpu_all();

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> data = <span class="hljs-keyword">self</span>.usage_data.lock().unwrap();
    <span class="hljs-keyword">for</span> (i, processor) <span class="hljs-keyword">in</span> sys.cpus().iter().enumerate() {
      data[i] = processor.cpu_usage();
    }
  }
}

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">create_ui</span></span>(state: &amp;Arc&lt;AppState&gt;) -&gt; LinearLayout {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> layout = LinearLayout::vertical();

    <span class="hljs-comment">// Title</span>
    layout.add_child(TextView::new(<span class="hljs-string">"CPU Monitor"</span>)
        .style(ColorStyle::title_primary())
        .h_align(HAlign::Center));
    layout.add_child(DummyView);

    <span class="hljs-comment">// CPU Cores Panel</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> cores_layout = LinearLayout::vertical();
    <span class="hljs-keyword">let</span> core_count = state.system.lock().unwrap().cpus().len();

    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-number">0</span>..core_count {
        cores_layout.add_child(
            TextView::new(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"Core {}: |"</span>, i))
                .style(ColorStyle::primary())
                .with_name(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"core_{}"</span>, i)),
        );
    }

    layout.add_child(Panel::new(cores_layout)
        .title(<span class="hljs-string">"CPU Usage"</span>));

    <span class="hljs-comment">// Footer</span>
    layout.add_child(DummyView);
    layout.add_child(TextView::new(<span class="hljs-string">"Press 'q' to quit"</span>)
        .style(ColorStyle::secondary())
        .h_align(HAlign::Center));

    layout
}

<span class="hljs-comment">// thread for updating the UI</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">start_update_thread</span></span>(ui_handle: cursive::CbSink, state: Arc&lt;AppState&gt;) {
    thread::spawn(<span class="hljs-keyword">move</span> || {
        <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(()) = ui_handle.send(<span class="hljs-built_in">Box</span>::new({
            <span class="hljs-keyword">let</span> state = Arc::clone(&amp;state);
            <span class="hljs-keyword">move</span> |s| {
                state.refresh_cpu_usage();
                <span class="hljs-keyword">let</span> data = state.usage_data.lock().unwrap();

                <span class="hljs-keyword">for</span> (i, usage) <span class="hljs-keyword">in</span> data.iter().enumerate() {
                    <span class="hljs-keyword">let</span> bar = generate_bar(*usage);
                    s.call_on_name(&amp;<span class="hljs-built_in">format!</span>(<span class="hljs-string">"core_{}"</span>, i), |view: &amp;<span class="hljs-keyword">mut</span> TextView| {
                        view.set_content(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"Core {:2} : {}"</span>, i, bar));
                    });
                }
            }
        })) {
            thread::sleep(Duration::from_secs(<span class="hljs-number">1</span>));
        }
    });
}

<span class="hljs-comment">// Simple ASCII progress bar</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">generate_bar</span></span>(usage: <span class="hljs-built_in">f32</span>) -&gt; <span class="hljs-built_in">String</span> {
    <span class="hljs-keyword">let</span> total_blocks = <span class="hljs-number">50</span>;
    <span class="hljs-keyword">let</span> filled_blocks = (usage / <span class="hljs-number">100.0</span> * total_blocks <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>).round() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;
    <span class="hljs-keyword">let</span> bar = <span class="hljs-string">"█"</span>.repeat(filled_blocks);
    <span class="hljs-keyword">let</span> empty = <span class="hljs-string">" "</span>.repeat(total_blocks - filled_blocks);
    <span class="hljs-built_in">format!</span>(<span class="hljs-string">"[{}{}] {:.2}%"</span>, bar, empty, usage)
}

<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> siv = Cursive::default();

    <span class="hljs-comment">// Customize theme</span>
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> theme = Theme::default();
    theme.palette[PaletteColor::Background] = Color::Rgb(<span class="hljs-number">30</span>, <span class="hljs-number">30</span>, <span class="hljs-number">30</span>);
    theme.palette[PaletteColor::View] = Color::Rgb(<span class="hljs-number">40</span>, <span class="hljs-number">40</span>, <span class="hljs-number">40</span>);
    theme.palette[PaletteColor::Primary] = Color::Rgb(<span class="hljs-number">0</span>, <span class="hljs-number">150</span>, <span class="hljs-number">150</span>);
    theme.palette[PaletteColor::Secondary] = Color::Rgb(<span class="hljs-number">100</span>, <span class="hljs-number">100</span>, <span class="hljs-number">100</span>);
    siv.set_theme(theme);

    <span class="hljs-keyword">let</span> state = AppState::new();
    <span class="hljs-keyword">let</span> layout = create_ui(&amp;state);
    siv.add_fullscreen_layer(layout);
    siv.add_global_callback(<span class="hljs-string">'q'</span>, |s| s.quit());
    start_update_thread(siv.cb_sink().clone(), Arc::clone(&amp;state));

    siv.run();
}
</code></pre>
<h2 id="heading-how-it-works">How It Works</h2>
<p>The code is ~100 lines and does the following:</p>
<ol>
<li><p>Initializes a struct <code>AppState</code> that holds a shared <code>System</code> instance and an array of CPU usage data, protected with mutexes.</p>
</li>
<li><p>Builds a UI layout using <code>Cursive</code>, showing:</p>
<ul>
<li><p>A title</p>
</li>
<li><p>A dynamically updating panel of all your CPU cores</p>
</li>
<li><p>A quit hint at the bottom</p>
</li>
</ul>
</li>
<li><p>Spawns a background thread that:</p>
<ul>
<li><p>Updates the CPU usage data every second</p>
</li>
<li><p>Sends updates to the UI thread via <code>cb_sink</code></p>
</li>
<li><p>Draws a simple ASCII progress bar for each core</p>
</li>
</ul>
</li>
</ol>
<p>Let’s break down a few key pieces.</p>
<h3 id="heading-shared-app-state">Shared App State</h3>
<pre><code class="lang-rust"><span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AppState</span></span> {
  system: Mutex&lt;System&gt;,
  usage_data: Mutex&lt;<span class="hljs-built_in">Vec</span>&lt;<span class="hljs-built_in">f32</span>&gt;&gt;,
}
</code></pre>
<p>All core CPU data is shared across threads using <code>Arc&lt;Mutex&lt;T&gt;&gt;</code>, allowing the update thread and UI thread to read/write safely.</p>
<h3 id="heading-the-ui-layout">The UI Layout</h3>
<pre><code class="lang-rust">TextView::new(<span class="hljs-string">"CPU Monitor"</span>)
  .style(ColorStyle::title_primary())
  .h_align(HAlign::Center);
</code></pre>
<p>Each core gets a <code>TextView</code> with a name like <code>core_0</code>, <code>core_1</code>, etc., so we can update it dynamically later.</p>
<pre><code class="lang-rust">s.call_on_name(&amp;<span class="hljs-built_in">format!</span>(<span class="hljs-string">"core_{}"</span>, i), |view: &amp;<span class="hljs-keyword">mut</span> TextView| {
    view.set_content(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"Core {:2} : {}"</span>, i, bar));
});
</code></pre>
<h3 id="heading-the-update-loop">The Update Loop</h3>
<pre><code class="lang-rust"><span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Ok</span>(()) = ui_handle.send(<span class="hljs-built_in">Box</span>::new({...})) {
  thread::sleep(Duration::from_secs(<span class="hljs-number">1</span>));
}
</code></pre>
<p>Inside this loop, the <code>AppState</code> is refreshed and each core’s usage is rendered as a bar using the <code>generate_bar</code> helper:</p>
<pre><code class="lang-rust"><span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">generate_bar</span></span>(usage: <span class="hljs-built_in">f32</span>) -&gt; <span class="hljs-built_in">String</span> {
    <span class="hljs-keyword">let</span> total_blocks = <span class="hljs-number">50</span>;
    <span class="hljs-keyword">let</span> filled_blocks = (usage / <span class="hljs-number">100.0</span> * total_blocks <span class="hljs-keyword">as</span> <span class="hljs-built_in">f32</span>).round() <span class="hljs-keyword">as</span> <span class="hljs-built_in">usize</span>;
    <span class="hljs-built_in">format!</span>(<span class="hljs-string">"[{}{}] {:.2}%"</span>, <span class="hljs-string">"█"</span>.repeat(filled_blocks), <span class="hljs-string">" "</span>.repeat(total_blocks - filled_blocks), usage)
}
</code></pre>
<h2 id="heading-understanding-arc-and-mutex-in-rust">Understanding Arc and Mutex in Rust</h2>
<p>This whole project revolves around safely sharing and updating data across threads. That’s where <code>Arc&lt;Mutex&lt;T&gt;&gt;</code> comes into play.</p>
<ul>
<li><p><code>Mutex&lt;T&gt;</code> lets us mutate shared data safely. It ensures that only one thread at a time can access the data inside.</p>
</li>
<li><p><code>Arc&lt;T&gt;</code> (Atomic Reference Counted pointer) allows multiple threads to hold ownership of the same value.</p>
</li>
</ul>
<p>Together, <code>Arc&lt;Mutex&lt;T&gt;&gt;</code> means:</p>
<blockquote>
<p>"Hey Rust, let multiple threads own this data, but make sure only one thread at a time can actually mutate it."</p>
</blockquote>
<p>Here’s what that looks like:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> data = Arc::new(Mutex::new(<span class="hljs-built_in">vec!</span>[<span class="hljs-number">0.0</span>; num_cores]));
</code></pre>
<p>Each thread that needs access clones the <code>Arc</code>:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> data_clone = Arc::clone(&amp;data);
</code></pre>
<p>Then locks the mutex before using the data:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> usage = data_clone.lock().unwrap();
usage[i] = new_value;
</code></pre>
<p>The lock gives you a mutable reference inside a <code>Result</code>, hence the <code>unwrap()</code> (or better: proper error handling).</p>
<h3 id="heading-run-the-example">Run The Example</h3>
<p>It’s time to see the result!! 😱</p>
<pre><code class="lang-bash">cargo run
</code></pre>
<p>You should see something similar.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1742755470506/db2eb0c1-e386-4f23-969d-39294445e29a.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[#2 Refactoring Fidely & Tackling Side Projects: Early 2025 Updates]]></title><description><![CDATA[Hello everyone,
It’s been a while since my last update in The 10-Minute Company series. I originally thought I’d be able to share progress sooner, but the holiday season (and a few unexpected projects) absorbed much of my free time. Nevertheless, I m...]]></description><link>https://pulbasso.dev/2-refactoring-fidely-tackling-side-projects-early-2025-updates</link><guid isPermaLink="true">https://pulbasso.dev/2-refactoring-fidely-tackling-side-projects-early-2025-updates</guid><category><![CDATA[Build In Public]]></category><category><![CDATA[SaaS]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Express]]></category><category><![CDATA[Testing]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Sun, 02 Feb 2025 11:18:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738494940144/61e420a4-9d43-4899-8135-60954b0d9201.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone,</p>
<p>It’s been a while since my last update in <em>The 10-Minute Company</em> series. I originally thought I’d be able to share progress sooner, but the holiday season (and a few unexpected projects) absorbed much of my free time. Nevertheless, I made some good progress—both on Fidely and on a smaller side project that popped up in early January.</p>
<h2 id="heading-a-quick-detour-building-a-landing-page-with-nextjs">A Quick Detour: Building a Landing Page with Next.js</h2>
<p>During the first two weeks of January, I helped a friend who offers online consultations by building a simple landing page for her services. The project was straightforward but fun, and it gave me a chance to work with:</p>
<ul>
<li><p><strong>Next.js</strong> for the frontend,</p>
</li>
<li><p><strong>Brevo</strong> (formerly Sendinblue) for handling newsletter subscriptions and automated emails,</p>
</li>
<li><p><strong>Brevo Meeting</strong> for scheduling online consultations,</p>
</li>
<li><p><strong>Clerk.com</strong> for authentication and an admin dashboard,</p>
</li>
<li><p><strong>Stripe</strong> for handling payments and checkout.</p>
</li>
</ul>
<p>One of the most interesting parts of the project was setting up an automated workflow: when someone subscribes to the newsletter and completes the <strong>double opt-in</strong>, they receive a <strong>welcome coupon code</strong> via email. This ensures only verified users get access to the special offer, adding an extra layer of engagement and trust.</p>
<p>Now, back to Fidely.</p>
<h2 id="heading-returning-to-fidely-cleaning-up-the-backend">Returning to Fidely: Cleaning Up the Backend</h2>
<p>With the side project wrapped up, I finally got back to working on Fidely. The focus of the last few days has been restructuring the backend to improve maintainability and scalability. Here’s what I worked on:</p>
<h3 id="heading-1-refactoring-api-routes">1. <strong>Refactoring API Routes</strong></h3>
<p>I split API endpoints more logically, ensuring that different resources and functionalities were correctly separated. This cleanup makes the backend easier to navigate and will help with future expansions.</p>
<p>Here’s a quick look at the updated routing system:</p>
<pre><code class="lang-rust">import { Router } from <span class="hljs-string">"express"</span>;
import authenticate from <span class="hljs-string">"../../middlewares/authenticate"</span>;
import authRoutes from <span class="hljs-string">"./auth"</span>;
import companiesRoutes from <span class="hljs-string">"./companies"</span>;
import campaignsRoutes from <span class="hljs-string">"./campaigns"</span>;
import cardCampaignsRoutes from <span class="hljs-string">"./card-campaigns"</span>;
import cardsRoutes from <span class="hljs-string">"./cards"</span>;
import transactionsRoutes from <span class="hljs-string">"./transactions"</span>;
import campaignBuildersRoutes from <span class="hljs-string">"./campaign-builders"</span>;

<span class="hljs-keyword">const</span> v1Routes = Router();

<span class="hljs-comment">// Public routes (no auth required)</span>
v1Routes.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/auth"</span>, authRoutes);

<span class="hljs-comment">// Protected routes</span>
v1Routes.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/companies"</span>, authenticate, companiesRoutes);
v1Routes.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/campaigns"</span>, authenticate, campaignsRoutes);
v1Routes.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/card-campaigns"</span>, authenticate, cardCampaignsRoutes);
v1Routes.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/cards"</span>, authenticate, cardsRoutes);
v1Routes.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/transactions"</span>, authenticate, transactionsRoutes);
v1Routes.<span class="hljs-keyword">use</span>(<span class="hljs-string">"/campaign-builders"</span>, authenticate, campaignBuildersRoutes);

export default v1Routes;
</code></pre>
<h3 id="heading-2-creating-a-simple-seeding-system">2. <strong>Creating a Simple Seeding System</strong></h3>
<p>Manually setting up test data was becoming a hassle, so I implemented an automated seeding script that:</p>
<ul>
<li><p>Clears the database,</p>
</li>
<li><p>Inserts fake data for testing and demo purposes.</p>
</li>
</ul>
<p>Here’s the updated seed system:</p>
<pre><code class="lang-rust">import { SeedContext } from './types';
import { seedUsers } from './users';
import { seedCompanies } from './companies';
import { seedCampaigns } from './campaigns';
import { seedCards } from './cards';

<span class="hljs-keyword">async</span> function main() {
  <span class="hljs-keyword">const</span> context: SeedContext = {
    users: {},
    companies: {},
    campaigns: {},
    cards: {},
    catalogs: {}
  };

  <span class="hljs-keyword">try</span> {
    console.log('🌱 Starting seed...');

    <span class="hljs-comment">// Seed users</span>
    console.log(<span class="hljs-symbol">'Seeding</span> users...');
    <span class="hljs-keyword">await</span> seedUsers(context);

    <span class="hljs-comment">// Seed companies</span>
    console.log(<span class="hljs-symbol">'Seeding</span> companies...');
    <span class="hljs-keyword">await</span> seedCompanies(context);

    <span class="hljs-comment">// Seed campaigns</span>
    console.log(<span class="hljs-symbol">'Seeding</span> campaigns...');
    <span class="hljs-keyword">await</span> seedCampaigns(context);

    <span class="hljs-comment">// Seed cards</span>
    console.log(<span class="hljs-symbol">'Seeding</span> cards...');
    <span class="hljs-keyword">await</span> seedCards(context);

    console.log('✅ Seed completed successfully!');
  } catch (error) {
    console.error('❌ Seed failed:', error);
    process.exit(<span class="hljs-number">1</span>);
  }
}

main();
</code></pre>
<p>One of the key advantages of using SQLite for both seeding and testing is the ability to spin up different databases for development and testing. This also allows for testing database migrations with Drizzle in a controlled environment.</p>
<h3 id="heading-3-introducing-automated-testing">3. <strong>Introducing Automated Testing</strong></h3>
<p>Fidely now has its first batch of automated tests! I’ve added both:</p>
<ul>
<li><p><strong>Unit tests</strong> for core logic,</p>
</li>
<li><p><strong>End-to-end (E2E) tests</strong> using Mocha and SuperAgent.</p>
</li>
</ul>
<p>This is just the beginning, but having a testing framework in place will make future development smoother and more reliable.</p>
<h2 id="heading-struggles-with-monorepos">Struggles with Monorepos</h2>
<p>One of the biggest challenges I’ve encountered (and still haven’t solved) is setting up a monorepo for both frontend and backend. Since the whole project is in TypeScript, a monorepo could help share code between them.</p>
<p>Yesterday, I spent several hours trying to migrate to <strong>pnpm workspaces</strong>, but I ran into issues with <strong>better-sqlite3</strong> during compilation. The new setup fails to find the compiled drivers—even after trying a <strong>postinstall recompilation</strong>, nothing changed. 😫</p>
<p>I haven’t figured out a solution yet, and for now, I don’t want to get stuck on this problem. If anyone has dealt with similar issues, I’d love to hear your thoughts! 🤔</p>
<h2 id="heading-next-steps">Next Steps</h2>
<p>I’m really happy with the backend refactor, and my next focus will be the frontend. The plan for the upcoming weeks includes:</p>
<ul>
<li><p>Enhancing the UI/UX,</p>
</li>
<li><p>Continuing to add automated tests,</p>
</li>
<li><p>Abstracting the transaction management system to allow for different transaction sources (currently, only operators can generate transactions).</p>
</li>
</ul>
<p>The overall goal remains the same: keeping the codebase clean and flexible so that Fidely can evolve naturally.</p>
<p>That’s it for this update! If you’ve worked on similar refactors, monorepos, or pnpm workspace issues, I’d love to hear your experiences. Let’s chat in the comments or via email!</p>
<p>Until next time! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[#1 Fidely: Loyalty App Side Project]]></title><description><![CDATA[Hello everyone,
Welcome to the first blog article of The 10-Minute Company series! Today, I’m excited to introduce Fidely, a simple digital loyalty app born from a conversation with a friend who owns a shop near my hometown.
He showed me his printed ...]]></description><link>https://pulbasso.dev/1-fidely-loyalty-app-side-project</link><guid isPermaLink="true">https://pulbasso.dev/1-fidely-loyalty-app-side-project</guid><category><![CDATA[Build In Public]]></category><category><![CDATA[side project]]></category><category><![CDATA[app development]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Fri, 13 Dec 2024 06:48:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734073464156/1afa17d4-47ae-4d4c-8667-292e7db3f4e0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone,</p>
<p>Welcome to the first blog article of <em>The 10-Minute Company</em> series! Today, I’m excited to introduce <strong>Fidely</strong>, a simple digital loyalty app born from a conversation with a friend who owns a shop near my hometown.</p>
<p>He showed me his printed stamp cards—those small cards that reward customers after they make a certain number of purchases. You’ve probably seen these before; they’re a straightforward way to build customer loyalty.</p>
<p>Fidely (a “spaghetti-English” twist on the word “Fidelity”) is essentially a digital version of these loyalty campaigns. It aims to make the process more modern and efficient.</p>
<h3 id="heading-what-does-fidely-do">What Does Fidely Do?</h3>
<p>Fidely supports two types of loyalty campaigns:</p>
<ul>
<li><p><strong>Points Collection</strong>: Shop owners can create a catalog where each reward requires a specific number of points to redeem.</p>
</li>
<li><p><strong>Stamp Campaigns</strong>: Similar to traditional stamp cards, where customers receive a reward after a set number of purchases.</p>
</li>
</ul>
<p>The system generates a unique virtual card for each customer, which they can use to collect points or stamps. What’s even better? The same card works in any shop using Fidely, creating a seamless loyalty experience.</p>
<h3 id="heading-why-did-i-build-this">Why Did I Build This?</h3>
<p>I started this project about a month ago, but with limited free time—just a few evenings and weekends. My goal is to provide an easy and affordable tool for shop owners to create customized loyalty campaigns. Beyond that, I hope Fidely fosters a local network of offers, connecting shops and their loyal customers.</p>
<p>With Fidely, shop owners can:</p>
<ul>
<li><p>Easily create virtual loyalty cards.</p>
</li>
<li><p>Engage customers through marketing emails or app notifications (future feature).</p>
</li>
<li><p>Build a community of interconnected businesses.</p>
</li>
</ul>
<p>Let’s take a closer look at where I’m at with the app.</p>
<h3 id="heading-the-web-app-current-features">The Web App: Current Features</h3>
<p>At this super early stage, Fidely is not even yet a proof of concept (PoC). Here’s what it can do so far:</p>
<ol>
<li><p><strong>Shop Owner Features:</strong></p>
<ul>
<li><p>Sign in with a pre-registered account.</p>
</li>
<li><p>View a basic dashboard with insights and quick links.</p>
</li>
<li><p>Create virtual cards for customers.</p>
</li>
<li><p>Launch two types of campaigns: points collection and stamp-based rewards.</p>
</li>
<li><p>Subscribe customer cards to campaigns.</p>
</li>
<li><p>Assign points to cards, track progress, and display rewards.</p>
</li>
</ul>
</li>
<li><p><strong>Customer Features:</strong></p>
<ul>
<li><p>Collect points or stamps on their virtual card.</p>
</li>
<li><p>Redeem rewards when reaching campaign goals.</p>
</li>
</ul>
</li>
</ol>
<p>Here’s a glimpse of the app in action:</p>
<h4 id="heading-login-page">Login Page</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734072026420/06c87f6f-c296-42f6-87ec-a22807ead454.png" alt /></p>
<h4 id="heading-home-dashboard">Home Dashboard</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734072060480/b6c13b3d-7be4-4d89-ac3e-ce3f657e3293.png" alt /></p>
<p>As you can see, the app is pretty unstyled and basic at this point. Localization is also missing, so enjoy some Italian text sprinkled in. :D</p>
<h4 id="heading-operator-dashboard">Operator Dashboard</h4>
<p>One feature I’m working on is the operator view. This allows shop employees to:</p>
<ul>
<li><p>Retrieve customer cards.</p>
</li>
<li><p>Assign points based on the current campaign.</p>
</li>
<li><p>Notify customers when they’ve earned a reward.</p>
</li>
</ul>
<p>Here’s a quick look at the operator’s workflow:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/_VzBYx7hecU">https://youtu.be/_VzBYx7hecU</a></div>
<p> </p>
<h4 id="heading-campaign-builder">Campaign Builder</h4>
<p>Shop owners can currently create stamp campaigns using this interface:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734072139962/615b8235-8d19-4d82-a46c-1f56c2c1e58f.png" alt /></p>
<p>Here, they can:</p>
<ul>
<li><p>Name the campaign.</p>
</li>
<li><p>Set the number of stamps required for a reward.</p>
</li>
<li><p>Assign values to stamps for easy tracking.</p>
</li>
<li><p>Define specific rewards for reaching milestones.</p>
</li>
</ul>
<h3 id="heading-my-development-approach">My Development Approach</h3>
<p>At this early stage, the app feels rough around the edges: bugs, inconsistent layouts, and no styling. But that’s intentional. Here’s how I approach side projects like Fidely:</p>
<ol>
<li><p><strong>Build a Dirty Prototype:</strong></p>
<ul>
<li><p>Focus on selecting the tech stack and setting it up.</p>
</li>
<li><p>Implement basic features to validate the idea.</p>
</li>
</ul>
</li>
</ol>
<p>    This phase helps me:</p>
<ul>
<li><p>See results quickly, keeping motivation high.</p>
</li>
<li><p>Identify design challenges early.</p>
</li>
<li><p>Understand which code modules are essential.</p>
</li>
</ul>
<ol start="2">
<li><p><strong>Refactor the Backend:</strong></p>
<ul>
<li><p>Review and clean up the codebase.</p>
</li>
<li><p>Organize routes and logic.</p>
</li>
<li><p>Write tests for stability.</p>
</li>
</ul>
</li>
<li><p><strong>Polish the Frontend:</strong></p>
<ul>
<li><p>Improve UX and layout consistency.</p>
</li>
<li><p>Refactor the frontend codebase for maintainability.</p>
</li>
</ul>
</li>
</ol>
<p>This incremental approach allows me to shift focus as needed, ensuring progress without getting overwhelmed. The key is identifying the minimal viable features to validate the idea while keeping the project flexible for future iterations.</p>
<h3 id="heading-whats-next">What’s Next?</h3>
<p>Now that the basic functionality is in place, I’ll focus on:</p>
<ul>
<li><p>Refactoring and structuring the backend.</p>
</li>
<li><p>Adding test coverage for reliability.</p>
</li>
<li><p>Organizing and improving the user interface.</p>
</li>
</ul>
<p>I’ll share updates as I go, though my free time varies, so posts may be sporadic.</p>
<p>I’d love to hear your thoughts! Have you tackled similar side projects? What development methodologies do you use? Let’s chat in the comments or via email!</p>
]]></content:encoded></item><item><title><![CDATA[#4 Daily Rabbit Holes: Cracking the Azure B2C Puzzle]]></title><description><![CDATA[Today was one of those days—a deep dive into the mysterious world of Azure B2C. Or, as I like to call it, a journey through the hidden labyrinth of Azure Identity.
For some reason, working with Azure Identity is never straightforward for me. Don’t ge...]]></description><link>https://pulbasso.dev/4-daily-rabbit-holes-cracking-the-azure-b2c-puzzle</link><guid isPermaLink="true">https://pulbasso.dev/4-daily-rabbit-holes-cracking-the-azure-b2c-puzzle</guid><category><![CDATA[Azure]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Wed, 04 Dec 2024 23:09:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733353593141/4407c98b-2708-448c-8fc3-6ea4eb811552.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today was one of <em>those</em> days—a deep dive into the mysterious world of Azure B2C. Or, as I like to call it, a journey through the hidden labyrinth of Azure Identity.</p>
<p>For some reason, working with Azure Identity is never straightforward for me. Don’t get me wrong—Microsoft Azure’s documentation can be excellent for many services. For example, setting up a basic Vision API project was a breeze, and I’d even say the .NET Core documentation is top-notch.</p>
<p>But Azure Identity? That’s a different story.</p>
<h3 id="heading-the-challenge">The Challenge</h3>
<p>I’ve worked with Microsoft Entra (the new branding for Azure Identity services) numerous times, and setting up an <strong>App Registration</strong> is something I’ve come to expect in my day-to-day tasks. Today, however, the goal was to explore <strong>Azure B2C</strong>.</p>
<h4 id="heading-what-is-azure-b2c">What Is Azure B2C?</h4>
<p>In simple terms, Azure B2C is a Microsoft service that allows you to create a <strong>white-labeled user management platform</strong>.</p>
<p>Think of it as an offshoot of Entra ID (formerly Azure Active Directory), tailored specifically for managing users who are external to your organization. While Entra ID is designed to handle internal users—employees, contractors, etc.—Azure B2C is aimed at customers or other external users.</p>
<p>With Azure B2C, you can:</p>
<ul>
<li><p>Create sign-up and sign-in flows</p>
</li>
<li><p>Customize the UI to match your brand</p>
</li>
<li><p>Handle password reset flows automatically</p>
</li>
<li><p>Integrate third-party identity providers like Google, Facebook, or Apple</p>
</li>
</ul>
<p>If you’re familiar with <strong>Auth0</strong> or <strong>Clerk</strong>, the concept is similar.</p>
<h3 id="heading-my-goal">My Goal</h3>
<p>Here were the requirements for my project:</p>
<ol>
<li><p><strong>Frontend:</strong> A React-based SPA (preferably with Vite).</p>
</li>
<li><p><strong>Authentication:</strong> Trusted user management using Azure B2C.</p>
</li>
<li><p><strong>Backend:</strong> Node.js or .NET Core API with bearer token authentication.</p>
</li>
</ol>
<p>It sounded simple enough. But the moment I started looking at the documentation, I found myself buried under outdated repositories, scattered information, and broken links.</p>
<h3 id="heading-the-struggle">The Struggle</h3>
<p>It’s a common scenario: a React SPA talking to a Node.js backend, secured with Azure B2C. Yet, the docs felt like a treasure hunt. I kept opening new tabs—at one point, I had over 20 Chrome tabs trying to piece everything together.</p>
<p>After hours of tinkering, I managed to get a basic example working:</p>
<ul>
<li><p>A React app (using <strong>Create React App</strong>, not Vite, unfortunately).</p>
</li>
<li><p>A Node.js backend (Express-based).</p>
</li>
</ul>
<h3 id="heading-resources-that-finally-worked">Resources That Finally Worked</h3>
<p>If you’re attempting the same setup, here are the key resources that worked for me:</p>
<h4 id="heading-frontend">Frontend:</h4>
<ul>
<li><a target="_blank" href="https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-react-samples/b2c-sample">MSAL React B2C Sample</a></li>
</ul>
<h4 id="heading-backend">Backend:</h4>
<ul>
<li><a target="_blank" href="https://github.com/Azure-Samples/active-directory-b2c-javascript-nodejs-webapi">Node.js Web API with Azure B2C</a></li>
</ul>
<h4 id="heading-azure-b2c-configuration">Azure B2C Configuration:</h4>
<ul>
<li><a target="_blank" href="https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-user-flow">Create User Flows</a></li>
</ul>
<p>Looking at these three links now, it feels so obvious. But finding and connecting them wasn’t easy.</p>
<h3 id="heading-observations">Observations</h3>
<p>Azure B2C and Microsoft Identity Platform are incredibly powerful, but navigating the documentation is challenging. Part of the issue seems to be the sheer breadth of features—combined with the need to support legacy systems like Active Directory.</p>
<p>In fairness, maintaining updated documentation while evolving services like Entra ID is no small feat.</p>
<h3 id="heading-whats-next">What’s Next?</h3>
<p>To streamline future projects, I’m building a small boilerplate using:</p>
<ul>
<li><p><strong>React + Vite + Tailwind + Shadcn</strong></p>
</li>
<li><p><strong>Azure B2C</strong> (or… maybe something else?)</p>
</li>
<li><p><strong>Node.js (Express + Passport)</strong></p>
</li>
</ul>
<p>Once it’s ready, I’ll update this article with the boilerplate.</p>
<h3 id="heading-the-plot-twist">The Plot Twist</h3>
<p>Every good rabbit hole has a twist, and this one’s no different.</p>
<p>Just as I wrapped my head around Azure B2C, I stumbled upon <strong>Microsoft Entra External ID</strong>—which, they claim, is even better.</p>
<p>Apparently, Azure B2C will eventually be replaced by Entra External ID. So, if you’re starting fresh, it might be worth exploring this newer option.</p>
<p>The rabbit hole continues…</p>
]]></content:encoded></item><item><title><![CDATA[The 10-Minute Company: A New Journey Begins]]></title><description><![CDATA[Hello everyone,
As I mentioned in a previous article, I’ve embarked on a new series called The 10-Minute Company. This idea has been on my to-do list for years. Now that it’s finally happening, I can’t decide whether to feel thrilled or terrified—pro...]]></description><link>https://pulbasso.dev/the-10-minute-company-a-new-journey-begins</link><guid isPermaLink="true">https://pulbasso.dev/the-10-minute-company-a-new-journey-begins</guid><category><![CDATA[Build In Public]]></category><category><![CDATA[side project]]></category><category><![CDATA[Series]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Mon, 02 Dec 2024 08:30:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733128084335/67ee8c69-cf47-4ec8-83fe-0ce122fb9ac0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone,</p>
<p>As I mentioned in a <a target="_blank" href="https://pul.hashnode.dev/3-daily-rabbit-holes-rust-useful-resources-deno-side-projects">previous article</a>, I’ve embarked on a new series called <em>The 10-Minute Company</em>. This idea has been on my to-do list for years. Now that it’s finally happening, I can’t decide whether to feel thrilled or terrified—probably a mix of both! Over the next few months, I’ll be dedicating significant effort to this project.</p>
<p>In short, the concept behind this series is simple: pick an idea (ideally a small one), develop it, and journal the process publicly. It aligns closely with the “build in public” philosophy but on a smaller, more approachable scale.</p>
<p>I’m fully aware this won’t be an easy journey. Creating software is already challenging, and doing it in public adds a whole new layer of difficulty—at least for me.</p>
<h2 id="heading-why-this-series">Why This Series?</h2>
<p>This is a challenge, no doubt about it, especially because it requires consistency. However, I believe the potential benefits make it worthwhile.</p>
<p>Before diving into my goals and expectations, let me share some context about my life and why I think this series could be beneficial, both for me and for others in my field.</p>
<h3 id="heading-a-few-facts-about-me">A Few Facts About Me</h3>
<ul>
<li><p>I love learning about tech-related topics, often after my daily work hours.</p>
</li>
<li><p>I rarely create tangible examples or demos for the challenges I explore.</p>
</li>
<li><p>My interests span various domains beyond software, which often spark ideas for my projects.</p>
</li>
<li><p>I enjoy designing software to solve specific problems.</p>
</li>
<li><p>My free time is limited.</p>
</li>
<li><p>I need a structured way to stay focused on my side projects.</p>
</li>
</ul>
<p>Since I began working in the field in 2011, I noticed that many job opportunities in the Italian tech scene came from consultancy firms that typically handle diverse projects and tech stacks. This led me to focus on broadening my knowledge across multiple topics, as it provided a more straightforward path to staying relevant and valuable in such a dynamic environment.</p>
<p>As a result, I adopted the habit of learning outside work, focusing on topics unrelated to my current job. This strategy has shaped my professional journey.</p>
<h3 id="heading-the-pros-and-cons-of-my-approach">The Pros and Cons of My Approach</h3>
<h4 id="heading-pros">Pros</h4>
<ul>
<li><p>Expanding knowledge while staying updated on trends and concepts.</p>
</li>
<li><p>Participating in developer meetups to learn from peers working on diverse projects.</p>
</li>
<li><p>Practicing coding and mastering new technologies.</p>
</li>
<li><p>Reducing job-related risks by broadening my skill set.</p>
</li>
<li><p>Connecting dots between technologies, architectures, and methodologies.</p>
</li>
<li><p>Discovering better solutions by knowing more options.</p>
</li>
<li><p>Identifying recurring patterns and requirements across different projects and tech stacks, which helps prioritize learning.</p>
</li>
</ul>
<h4 id="heading-cons">Cons</h4>
<ul>
<li><p><strong>Time constraints</strong>: The day is still only 24 hours, and this approach has forced me to sacrifice other passions.</p>
</li>
<li><p><strong>Surface-level engagement</strong>: While I value adaptability, I sometimes feel that “use the right tool for the job” oversimplifies reality. Learning a new framework or language should be a necessity that arises after maximizing the tools already at your disposal.</p>
</li>
<li><p><strong>Misaligned perceptions</strong>: Some employers—especially those outside the tech core business—fail to recognize the value of this knowledge. This can lead to undervaluing professional expertise and bypassing important processes like documentation, skill development, and fostering innovation.</p>
</li>
</ul>
<h2 id="heading-a-shift-in-perspective">A Shift in Perspective</h2>
<p>While my focus on continuous learning has served me well, it’s time to shift gears. I want to channel the skills I’ve built over the years into concrete projects. Instead of just expanding my knowledge, I’ll now prioritize applying it to bring my ideas to life.</p>
<p>This blog and the <em>10-Minute Company</em> series are tools to keep me focused and accountable. Turning an idea into a working example requires a mix of skills—not just coding—which will push me to explore new perspectives.</p>
<p>I’m excited about the opportunity to grow, not only technically but also in terms of communication and networking.</p>
<p>I’d love to hear your thoughts! Any constructive feedback or support you can offer would make a huge difference in keeping this series alive and thriving.</p>
]]></content:encoded></item><item><title><![CDATA[DevFest Milano 2024]]></title><description><![CDATA[Last week, I had the pleasure of attending DevFest Milan 2024, an event organized by GDG (Google Developer Groups) communities worldwide.
Living in a small town on the Ligurian west coast has its perks—better quality of life, stunning views, and a sl...]]></description><link>https://pulbasso.dev/devfest-milano-2024</link><guid isPermaLink="true">https://pulbasso.dev/devfest-milano-2024</guid><category><![CDATA[devfest2024]]></category><category><![CDATA[conference]]></category><category><![CDATA[milano]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Sat, 30 Nov 2024 21:44:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732492404298/b1893105-bebf-4d40-b230-e43d2bbeb1b9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week, I had the pleasure of attending <strong>DevFest Milan 2024</strong>, an event organized by GDG (Google Developer Groups) communities worldwide.</p>
<p>Living in a small town on the Ligurian west coast has its perks—better quality of life, stunning views, and a slower pace—but networking opportunities for developers are rare. Most of the time, I rely on online communities to stay connected. That’s why, when I stumbled across this conference on Eventbrite, I didn’t think twice before grabbing a ticket (which, by the way, was free!).</p>
<p>The event was held in Milan, attracting a mix of local developers, students, and even attendees from abroad. It was wonderful to experience such an inclusive and welcoming atmosphere.</p>
<h3 id="heading-a-spotlight-on-ai">A Spotlight on AI</h3>
<p>The conference heavily focused on <strong>artificial intelligence</strong>, which makes perfect sense given its prominence in tech over the past few years. Here are the talks I attended:</p>
<ul>
<li><p><strong>Dealing with GenAI agents and rapid-fire messaging</strong></p>
</li>
<li><p><strong>Da Documenti Statici a Risposte Immediate: La Rivoluzione AI nel Settore Industriale</strong></p>
</li>
<li><p><strong>Dagli atomi ai template: Come sviluppare un design system senza perderci la testa!</strong></p>
</li>
<li><p><strong>Gemini Functions Calls in Flutter</strong></p>
</li>
<li><p><strong>SLSA on GCP: Let's Mitigate Supply Chain Threats</strong></p>
</li>
<li><p><strong>Pretotyping in the Real World - Quickly Iterating Between Good and Bad Startup Ideas</strong></p>
</li>
<li><p><strong>Generative AI Unveiled: From Fundamentals to Real-World Applications</strong></p>
</li>
<li><p><strong>Bringing Fictional Characters to Life with Open Source LLMs</strong></p>
</li>
</ul>
<p>The conference was well-organized, and every talk I attended was engaging and informative. Let me share some highlights from my favorite sessions.</p>
<h3 id="heading-highlights-from-the-talks">Highlights from the Talks</h3>
<h4 id="heading-dealing-with-genai-agents-and-rapid-fire-messaging"><strong>Dealing with GenAI Agents and Rapid-Fire Messaging</strong></h4>
<p>This talk by <a target="_blank" href="https://linkedin.com/in/danilotrombino/en"><strong>Danilo Trombino</strong></a> explored a fascinating aspect of AI chatbots that I hadn’t considered before: managing user interactions in real-time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733000756785/15b4f6aa-2d75-45dd-9c70-f64c449ff52a.png" alt class="image--center mx-auto" /></p>
<p>Different users communicate differently—some send fully detailed messages in one go, while others prefer a “chatty” style, breaking their thoughts into multiple short messages. Adding to the complexity, the time users take to type their messages can also vary significantly.</p>
<p>Danilo introduced a clever solution to handle these challenges using <strong>Redis</strong>. By assigning an expiring key to each user’s message, Redis tracks activity in real-time. If no new messages are sent within a specific time frame, the expiration triggers a request to the AI. This approach not only minimizes unnecessary calls to the AI service but also supports scalability by using Redis as a centralized system across multiple application instances.</p>
<p>The insights were practical, and Danilo’s clear explanations made it one of the standout talks for me.</p>
<h4 id="heading-da-documenti-statici-a-risposte-immediate-la-rivoluzione-ai-nel-settore-industriale"><strong>Da Documenti Statici a Risposte Immediate: La Rivoluzione AI nel Settore Industriale</strong></h4>
<p>This was easily my favorite talk of the conference. While the topic—building a <strong>retrieval-augmented generation (RAG)</strong> system for internal documentation—might not sound glamorous, <a target="_blank" href="https://www.linkedin.com/in/desimonechristian/"><strong>Christian</strong></a> <strong>and</strong> <a target="_blank" href="https://www.linkedin.com/in/andrea-caglio/"><strong>Andrea</strong></a> brought it to life by sharing real-world challenges they faced while implementing the system for a large client.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733001663513/b6f1cd38-150d-4829-8f5f-a86d89c8068b.png" alt class="image--center mx-auto" /></p>
<p>Their use of <strong>Haystack</strong> pipelines to process and integrate data with ChatGPT-based assistants was inspiring. It was a reminder of what I love most about my work: solving real problems. A system like this can genuinely improve a company’s efficiency, and the way they tackled these challenges was nothing short of impressive.</p>
<h4 id="heading-gemini-functions-calls-in-flutter"><strong>Gemini Functions Calls in Flutter</strong></h4>
<p>Though I’ve never worked with Flutter, <a target="_blank" href="https://www.linkedin.com/in/clucera/"><strong>Carlo Lucera</strong></a> made this talk highly accessible. He walked us through a practical example of using <strong>Gemini function calls</strong> in a Flutter app to retrieve real-time information about DevFests worldwide.</p>
<p>It was a well-structured session, and Carlo’s clarity in explaining the integration made me curious to try Flutter in the future.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733001719872/53ffaff8-5928-4314-9f5d-6e572a401b74.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-generative-ai-unveiled-from-fundamentals-to-real-world-applications"><strong>Generative AI Unveiled: From Fundamentals to Real-World Applications</strong></h4>
<p><a target="_blank" href="https://linkedin.com/in/levinyonatan"><strong>Yonatan Levin</strong></a> delivered a thought-provoking talk on optimizing search results in RAG systems using <strong>graph databases</strong> for embeddings. The ideas were advanced yet presented in a way that was easy to follow.</p>
<p>Unfortunately, the session ended before there was time for Q&amp;A. I’d love to see a sequel to this talk in a future conference—it definitely left me wanting more!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733001993620/6ac5f3db-150d-4013-84fd-710e69e9cc40.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Attending DevFest Milan 2024 was a refreshing experience. While the topics weren’t overly advanced, they struck the right balance for a community-driven event that aims to engage developers of all levels.</p>
<p>If you’re a developer looking for inspiration, networking, or just a reason to step away from your screen, I’d highly recommend keeping an eye out for the next DevFest near you. And if you’re lucky enough to live close to Milan, don’t miss it!</p>
]]></content:encoded></item><item><title><![CDATA[#3 Daily Rabbit Holes: Rust Useful Resources + Deno + Side Projects]]></title><description><![CDATA[Today, like the past few days, I’ve spent nearly all my free time diving into the Rust + Deno ecosystem. It’s a rabbit hole I can’t seem to escape—but I’m loving every second of it!
Here’s a list of links and resources I’ve come across that seem part...]]></description><link>https://pulbasso.dev/3-daily-rabbit-holes-rust-useful-resources-deno-side-projects</link><guid isPermaLink="true">https://pulbasso.dev/3-daily-rabbit-holes-rust-useful-resources-deno-side-projects</guid><category><![CDATA[DailyRabbitHoles]]></category><category><![CDATA[Rust]]></category><category><![CDATA[rust lang]]></category><category><![CDATA[Rust programming]]></category><category><![CDATA[Deno]]></category><category><![CDATA[side project]]></category><category><![CDATA[Build In Public]]></category><category><![CDATA[dailydev]]></category><category><![CDATA[journal]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Thu, 28 Nov 2024 22:41:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733003740678/b482cb1f-d4dc-49b3-ac1f-7c99fc48969e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today, like the past few days, I’ve spent nearly all my free time diving into the <strong>Rust</strong> + <strong>Deno</strong> ecosystem. It’s a rabbit hole I can’t seem to escape—but I’m loving every second of it!</p>
<p>Here’s a list of links and resources I’ve come across that seem particularly valuable. Some are comprehensive collections, so it’ll take a bit of time to figure out which ones to follow deeply.</p>
<p>As a general rule, I don’t want to learn <strong>Rust</strong> by watching endless tutorials. Instead, I prefer a hands-on approach: reading interesting codebases and experimenting directly.</p>
<p>As a <strong>Node.js</strong> developer, I find <strong>Deno</strong> fascinating. It’s a project that offers so much to learn, from low-level programming concepts to building finished products.</p>
<p>Here’s a list of the best resources I discovered today:</p>
<h4 id="heading-recommended-resources">Recommended Resources</h4>
<ul>
<li><p><a target="_blank" href="https://github.com/google/comprehensive-rust"><strong>Comprehensive Rust</strong></a><br />  A very well-written “book” by the Android Team at Google.</p>
</li>
<li><p><a target="_blank" href="https://gist.github.com/cedrickchee/f729e848b52eab8fbc88a3910072198c"><strong>Rust Resources List</strong></a><br />  An “awesome” list with tons of useful links, especially the blog section.</p>
</li>
<li><p><a target="_blank" href="https://www.ralfj.de/projects/rust-101/main.html"><strong>Rust 101</strong></a><br />  Covers topics from basics to advanced. It’s concise—maybe too concise—but that could be a plus if you don’t want to spend too much time on tutorials.</p>
</li>
<li><p><a target="_blank" href="https://github.com/ImplFerris/LearnRust"><strong>LearnRust</strong></a><br />  A highly curated list for all expertise levels.</p>
</li>
<li><p><a target="_blank" href="https://choubey.gitbook.io/internals-of-deno/architecture/core"><strong>Internals of Deno</strong></a><br />  At the moment, this is the most interesting one for me. It dives into Deno’s architecture and internals.</p>
</li>
</ul>
<p>I’ve decided to start with the last one since I’m really curious about how Deno works behind the scenes (at least at a high level). Over the past few days, I’ve particularly enjoyed learning about V8 isolates.</p>
<p>I’ll keep you updated if I discover more interesting resources!</p>
<hr />
<h3 id="heading-when-rust-and-deno-take-over-your-side-projects">When Rust and Deno Take Over Your Side Projects</h3>
<p>Okay, the title might be a bit long and clunky, but it perfectly sums up my current situation. I’m enjoying learning about <strong>V8</strong>, <strong>Rust</strong>, and <strong>Deno</strong>, but it’s eating up way too much of my free time.</p>
<p>I’m sure I’m not alone in struggling to find the right balance between work, life, side projects, and study.</p>
<p>Last month, I started a new side project—simple enough for a solo developer (at least in its early stages) but interesting enough to eventually grow into a real product.</p>
<p>For me, one of the best parts of my job is creating software or products that can improve people’s daily lives.</p>
<p>I don’t think you need a groundbreaking idea to create a good product. Often, just listening to people or friends is enough to uncover small niches where you can build something useful.</p>
<p>This process is a great way to improve all the skills related to product development—and I’m not just talking about coding. It’s also about system design, writing good requirements, documentation, choosing the right tools, testing the market, gathering feedback, finding early adopters, and so much more.</p>
<p>In the next few days, I’ll write a blog post to introduce my new side project. My goal is to keep it alive, at least until I have a working proof of concept.</p>
<hr />
<h3 id="heading-introducing-the-10-minute-company">Introducing <em>The 10-Minute Company</em></h3>
<p>To stay focused on developing my project, I’ve decided to share my journey in a new series called <strong>“The 10-Minute Company”</strong>. I’ll document my side projects, starting from scratch and working toward a functional PoC.</p>
<p>Stay tuned for all the details! 🚀</p>
]]></content:encoded></item><item><title><![CDATA[#2 Daily Rabbit Holes: Diving Deeper into Rust, V8, and the JavaScript™️ Saga]]></title><description><![CDATA[Unfortunately, today I had very little time to dive into interesting topics. I spent some time on a side project (which I’ll probably write about in the coming days), worked on my day job, and did some sports. Still, my focus remains on Deno, Rust, a...]]></description><link>https://pulbasso.dev/2-daily-rabbit-holes-diving-deeper-into-rust-v8-and-the-javascript-saga</link><guid isPermaLink="true">https://pulbasso.dev/2-daily-rabbit-holes-diving-deeper-into-rust-v8-and-the-javascript-saga</guid><category><![CDATA[Rust]]></category><category><![CDATA[V8]]></category><category><![CDATA[rust lang]]></category><category><![CDATA[Rust programming]]></category><category><![CDATA[rustseries]]></category><category><![CDATA[journal]]></category><category><![CDATA[Deno]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Tue, 26 Nov 2024 22:24:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733003641316/58a7553d-85a6-475a-84d6-9ad3dd30ad04.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Unfortunately, today I had very little time to dive into interesting topics. I spent some time on a side project (which I’ll probably write about in the coming days), worked on my day job, and did some sports. Still, my focus remains on <strong>Deno</strong>, <strong>Rust</strong>, and the <strong>V8 engine</strong>, just like in my <a target="_blank" href="https://pul.hashnode.dev/1-daily-rabbit-holes-rusty-v8-nodejs-and-deno">previous article</a>.</p>
<p>I managed to review the <a target="_blank" href="https://dzx.cz/2023-03-08/how_do_cloudflare_workers_work/">fantastic article</a> by <a target="_blank" href="https://dzx.cz/about/">Matouš Dzivjak</a>, where he explains how to build a runtime using <strong>Rust V8</strong>.</p>
<p>The code from the article is a bit outdated and doesn’t run with the current version of Rust. I managed to get it working somehow, even though I don’t actually know Rust yet (so it’s either an easy task or I just got really lucky).</p>
<p>Below is the updated code with minor tweaks and some comments to help with understanding. All credits, of course, go to Matouš.</p>
<h3 id="heading-quick-breakdown">Quick Breakdown</h3>
<p>This code demonstrates how to build a <strong>minimal JavaScript runtime using Rust</strong> and the <strong>V8 engine</strong>:</p>
<ul>
<li><p><strong>Platform and V8 Initialization:</strong> The <a target="_blank" href="http://main.rs">main.rs</a> file initializes the V8 engine and platform, preparing it to execute JavaScript code.</p>
</li>
<li><p><strong>Runtime Setup:</strong> A global object (<em>globalThis.workerHandler</em>) is exposed in the runtime using JavaScript, enabling a Rust function to be callable from JavaScript.</p>
</li>
<li><p><strong>Script Compilation:</strong> The build_worker function compiles and evaluates the JavaScript code, combining the <em>runtime script</em> and a <em>worker_script</em> that defines a handler function.</p>
</li>
<li><p><strong>Global Context Binding:</strong> Rust functions, such as <em>sayHello</em>, are exposed to the V8 runtime by binding them to global object properties.</p>
</li>
<li><p><strong>Function Execution:</strong> The run_worker function calls the JavaScript handler function from Rust, passing parameters and printing the result (Hello World) to the console.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-comment">// runtime.js</span>
globalThis.workerHandler = <span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> { 
  <span class="hljs-keyword">return</span> handler(x);
}
</code></pre>
<pre><code class="lang-rust"><span class="hljs-comment">// main.rs</span>
<span class="hljs-keyword">use</span> v8;

<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() {
    <span class="hljs-comment">// Platform and V8 initialization</span>
    <span class="hljs-keyword">let</span> platform = v8::Platform::new(<span class="hljs-number">0</span>, <span class="hljs-literal">false</span>).make_shared();
    v8::V8::initialize_platform(platform);
    v8::V8::initialize();
    <span class="hljs-comment">// `include_str!` is a Rust macro that loads a file and converts it into a Rust string</span>
    <span class="hljs-keyword">let</span> runtime = <span class="hljs-built_in">include_str!</span>(<span class="hljs-string">"runtime.js"</span>);

    <span class="hljs-keyword">let</span> worker_script = <span class="hljs-string">r#"
    export function handler(y) {
        return sayHello(y);
    };
    "#</span>;
    <span class="hljs-comment">// The runtime.js file exposes the `handler` function as a global object</span>
    <span class="hljs-keyword">let</span> script = <span class="hljs-built_in">format!</span>(
        <span class="hljs-string">r#"
        {runtime}
        {worker_script}
        "#</span>
    );

    {
        <span class="hljs-comment">// Create a V8 isolate with default parameters</span>
        <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> isolate = v8::Isolate::new(v8::CreateParams::default());
        <span class="hljs-keyword">let</span> global = setup_runtime(&amp;<span class="hljs-keyword">mut</span> isolate);
        <span class="hljs-keyword">let</span> worker_scope = &amp;<span class="hljs-keyword">mut</span> v8::HandleScope::with_context(isolate.as_mut(), global.clone());
        <span class="hljs-keyword">let</span> handler = build_worker(script.as_str(), worker_scope, &amp;global);
        run_worker(handler, worker_scope, &amp;global);
    }

    <span class="hljs-keyword">unsafe</span> {
        v8::V8::dispose();
    }
    v8::V8::dispose_platform();
}
<span class="hljs-comment">// Set up the global runtime context</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">setup_runtime</span></span>(isolate: &amp;<span class="hljs-keyword">mut</span> v8::OwnedIsolate) -&gt; v8::Global&lt;v8::Context&gt; {
    <span class="hljs-comment">// Create a handle scope for all isolate handles    </span>
    <span class="hljs-keyword">let</span> isolate_scope = &amp;<span class="hljs-keyword">mut</span> v8::HandleScope::new(isolate);
    <span class="hljs-comment">// ObjectTemplate is used to create objects inside the isolate</span>
    <span class="hljs-keyword">let</span> globals = v8::ObjectTemplate::new(isolate_scope);
    <span class="hljs-comment">// The function name to bind to the Rust implementation</span>
    <span class="hljs-keyword">let</span> resource_name = v8::<span class="hljs-built_in">String</span>::new(isolate_scope, <span class="hljs-string">"sayHello"</span>).unwrap().into();
    <span class="hljs-comment">// Expose the function to the global object</span>
    globals.set(
        resource_name,
        v8::FunctionTemplate::new(isolate_scope, say_hello_binding).into()
    );
    <span class="hljs-comment">// Create a context for isolate execution</span>
    <span class="hljs-keyword">let</span> context_options = v8::ContextOptions {
        global_template: <span class="hljs-literal">Some</span>(globals),
        ..<span class="hljs-built_in">Default</span>::default()
    };
    <span class="hljs-keyword">let</span> global_context = v8::Context::new(isolate_scope, context_options);
    <span class="hljs-comment">// Create and return the global context</span>
    v8::Global::new(isolate_scope, global_context)
}
<span class="hljs-comment">// Define the Rust binding for the sayHello function</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">say_hello_binding</span></span>(
    scope: &amp;<span class="hljs-keyword">mut</span> v8::HandleScope,
    args: v8::FunctionCallbackArguments,
    <span class="hljs-keyword">mut</span> retval: v8::ReturnValue,
) {
    <span class="hljs-keyword">let</span> to = args.get(<span class="hljs-number">0</span>).to_rust_string_lossy(scope);
    <span class="hljs-keyword">let</span> hello = v8::<span class="hljs-built_in">String</span>::new(scope, <span class="hljs-built_in">format!</span>(<span class="hljs-string">"Hello {}"</span>, to).as_str())
    .unwrap().into();
    retval.set(hello);
}
<span class="hljs-comment">// Build the worker by compiling and instantiating the script</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">build_worker</span></span>(
    script: &amp;<span class="hljs-built_in">str</span>,
    worker_scope: &amp;<span class="hljs-keyword">mut</span> v8::HandleScope,
    global: &amp;v8::Global&lt;v8::Context&gt;,
) -&gt; v8::Global&lt;v8::Function&gt; {
    <span class="hljs-keyword">let</span> code = v8::<span class="hljs-built_in">String</span>::new(worker_scope, script).unwrap();
    <span class="hljs-keyword">let</span> resource_name = v8::<span class="hljs-built_in">String</span>::new(worker_scope, <span class="hljs-string">"script.js"</span>).unwrap().into();
    <span class="hljs-comment">// The source map is optional and used for debugging purposes</span>
    <span class="hljs-keyword">let</span> source_map_url: <span class="hljs-built_in">Option</span>&lt;v8::Local&lt;<span class="hljs-symbol">'_</span>, v8::Value&gt;&gt; = <span class="hljs-literal">Some</span>(v8::<span class="hljs-built_in">String</span>::new(worker_scope, <span class="hljs-string">"placeholder"</span>).unwrap().into());
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> source = v8::script_compiler::Source::new(
        code,
        <span class="hljs-literal">Some</span>(&amp;v8::ScriptOrigin::new(
            worker_scope,
            resource_name,
            <span class="hljs-number">0</span>,
            <span class="hljs-number">0</span>,
            <span class="hljs-literal">false</span>,
            <span class="hljs-built_in">i32</span>::from(<span class="hljs-number">0</span>),
            source_map_url,
            <span class="hljs-literal">false</span>,
            <span class="hljs-literal">false</span>,
            <span class="hljs-literal">true</span>,
            <span class="hljs-literal">None</span>
        )),
    );
    <span class="hljs-comment">// Compile and evaluate the module</span>
    <span class="hljs-keyword">let</span> module = v8::script_compiler::compile_module(worker_scope, &amp;<span class="hljs-keyword">mut</span> source).unwrap();
    <span class="hljs-keyword">let</span> _ = module.instantiate_module(worker_scope, |_, _, _, _| <span class="hljs-literal">None</span>);
    <span class="hljs-keyword">let</span> _ = module.evaluate(worker_scope);
    <span class="hljs-comment">// open a global scope associated to the worker_scope</span>
    <span class="hljs-keyword">let</span> global = global.open(worker_scope);
    <span class="hljs-comment">// create and assign the handler to the global context</span>
    <span class="hljs-keyword">let</span> global = global.global(worker_scope);
    <span class="hljs-keyword">let</span> handler_key = v8::<span class="hljs-built_in">String</span>::new(worker_scope, <span class="hljs-string">"workerHandler"</span>).unwrap();
    <span class="hljs-keyword">let</span> js_handler = global.get(worker_scope, handler_key.into()).unwrap();    
    <span class="hljs-keyword">let</span> local_handler = v8::Local::&lt;v8::Function&gt;::try_from(js_handler).unwrap();
    v8::Global::new(worker_scope, local_handler)
}

<span class="hljs-comment">// Run the worker and execute the `handler` function</span>
<span class="hljs-keyword">pub</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">run_worker</span></span>(
    worker: v8::Global&lt;v8::Function&gt;,
    scope: &amp;<span class="hljs-keyword">mut</span> v8::HandleScope,
    global: &amp;v8::Global&lt;v8::Context&gt;,
) {
    <span class="hljs-keyword">let</span> handler = worker.open(scope);
    <span class="hljs-keyword">let</span> global = global.open(scope);
    <span class="hljs-keyword">let</span> global = global.global(scope);

    <span class="hljs-keyword">let</span> param = v8::<span class="hljs-built_in">String</span>::new(scope, <span class="hljs-string">"World"</span>).unwrap().into();
    <span class="hljs-comment">// call the handler and get the result</span>
    <span class="hljs-keyword">match</span> handler.call(scope, global.into(), &amp;[param]) {
        <span class="hljs-literal">Some</span>(response) =&gt; {
            <span class="hljs-keyword">let</span> result = v8::Local::&lt;v8::<span class="hljs-built_in">String</span>&gt;::try_from(response)
                .expect(<span class="hljs-string">"Handler did not return a string"</span>);
            <span class="hljs-keyword">let</span> result = result.to_string(scope).unwrap();
            <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{}"</span>, result.to_rust_string_lossy(scope));
        }
        <span class="hljs-literal">None</span> =&gt; todo!(),
    };
}
</code></pre>
<p>I strongly encourage you to read Matouš Dzivjak’s excellent article for a deeper dive into the code and its concepts. This was just a summary—his detailed explanations are essential for understanding the technical nuances!</p>
<h2 id="heading-javascript-petition">JavaScript Petition!</h2>
<p>By the way, I had completely forgotten that Oracle owns the <strong>JavaScript</strong> trademark—something I already knew but slipped my mind. This week, Deno’s petition to cancel the trademark served as a reminder of this curious fact.</p>
<p>If you're interested in learning more, check out:</p>
<ul>
<li><p><a target="_blank" href="https://javascript.tm/">https://javascript.tm/</a></p>
</li>
<li><p><a target="_blank" href="https://deno.com/blog/deno-v-oracle">https://deno.com/blog/deno-v-oracle</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[#1 Daily Rabbit Holes: Rusty V8, Node.js and Deno]]></title><description><![CDATA[This series is essentially a notebook where I document the things I learn online during my limited free time—usually early in the morning or late at night.
Today’s rabbit hole started with Deno Deploy, which powers serverless functions for services l...]]></description><link>https://pulbasso.dev/1-daily-rabbit-holes-rusty-v8-nodejs-and-deno</link><guid isPermaLink="true">https://pulbasso.dev/1-daily-rabbit-holes-rusty-v8-nodejs-and-deno</guid><category><![CDATA[Rust]]></category><category><![CDATA[rust lang]]></category><category><![CDATA[V8]]></category><category><![CDATA[rustseries]]></category><category><![CDATA[learning]]></category><category><![CDATA[learn]]></category><category><![CDATA[#learning-in-public]]></category><dc:creator><![CDATA[pul]]></dc:creator><pubDate>Mon, 25 Nov 2024 23:53:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732578670116/9422dc40-b8ab-476d-9736-551beb49179f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This series is essentially a notebook where I document the things I learn online during my limited free time—usually early in the morning or late at night.</p>
<p>Today’s rabbit hole started with <a target="_blank" href="https://deno.com/deploy">Deno Deploy</a>, which powers serverless functions for services like <a target="_blank" href="https://supabase.com/">Supabase</a> and <a target="_blank" href="https://www.netlify.com/">Netlify</a>.</p>
<p>Unlike traditional serverless environments such as AWS Lambda, which rely on micro-VMs (via <a target="_blank" href="https://firecracker-microvm.github.io/">Firecracker</a>) or containers, Deno Deploy uses <strong>V8 Isolates</strong>. Intrigued, I decided to dive deeper into <strong>Rusty V8</strong>—the Rust bindings for V8—and learn more about how isolates work.</p>
<p>Here’s the repo: <a target="_blank" href="https://github.com/denoland/rusty_v8">github.com/denoland/rusty_v8</a></p>
<p>I’m learning Rust alongside many other interests, and I’ve found that reading codebases I’m genuinely curious about is one of the best ways to pick up a new language, explore concepts, and understand technologies.</p>
<p>That said, this is a rough overview of my findings so far. There might be errors, but consider this post a starting point for your own rabbit hole! 😄</p>
<hr />
<h2 id="heading-exploring-the-codebase">Exploring the Codebase</h2>
<p>I started exploring the <code>rusty_v8</code> codebase and was impressed by how closely it mirrors the original V8 implementation. This alignment makes it easier to find relevant documentation and examples online.</p>
<p>The code is well-organized, and I focused on how the bindings reference the underlying V8 code.</p>
<h3 id="heading-backingstore-memory-behind-the-scenes">BackingStore: Memory Behind the Scenes</h3>
<p>One interesting discovery was the <strong>ArrayBuffer</strong>, a contiguous block of memory used to store binary data. What caught my attention was the <strong>BackingStore</strong>—an abstraction that manages the raw memory backing the ArrayBuffer.</p>
<p>In simpler terms, the BackingStore represents the memory area (allocated by the operating system) where the data of an ArrayBuffer is stored. V8 handles this memory, including garbage collection, ensuring efficient memory management.</p>
<hr />
<h2 id="heading-inside-the-v8-engine">Inside the V8 Engine</h2>
<p>Curious about how V8 works at a deeper level, I turned to its <a target="_blank" href="https://v8.dev/docs">official documentation</a>. Given the complexity of the project, I decided to approach it as a "black box" and started by reading how to embed V8 into an application.</p>
<p>A great resource was the <a target="_blank" href="https://v8.dev/docs/embed">hello world example</a>, which demonstrates embedding V8 in a C++ application. Rusty V8 provides a similar example:</p>
<pre><code class="lang-rust">rustCopia codicelet platform = v8::new_default_platform(<span class="hljs-number">0</span>, <span class="hljs-literal">false</span>).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();

<span class="hljs-keyword">let</span> isolate = &amp;<span class="hljs-keyword">mut</span> v8::Isolate::new(<span class="hljs-built_in">Default</span>::default());

<span class="hljs-keyword">let</span> scope = &amp;<span class="hljs-keyword">mut</span> v8::HandleScope::new(isolate);
<span class="hljs-keyword">let</span> context = v8::Context::new(scope, <span class="hljs-built_in">Default</span>::default());
<span class="hljs-keyword">let</span> scope = &amp;<span class="hljs-keyword">mut</span> v8::ContextScope::new(scope, context);

<span class="hljs-keyword">let</span> code = v8::<span class="hljs-built_in">String</span>::new(scope, <span class="hljs-string">"'Hello' + ' World!'"</span>).unwrap();
<span class="hljs-built_in">println!</span>(<span class="hljs-string">"JavaScript code: {}"</span>, code.to_rust_string_lossy(scope));

<span class="hljs-keyword">let</span> script = v8::Script::compile(scope, code, <span class="hljs-literal">None</span>).unwrap();
<span class="hljs-keyword">let</span> result = script.run(scope).unwrap();
<span class="hljs-keyword">let</span> result = result.to_string(scope).unwrap();
<span class="hljs-built_in">println!</span>(<span class="hljs-string">"Result: {}"</span>, result.to_rust_string_lossy(scope));
</code></pre>
<p>This example introduces four key concepts in V8:</p>
<ul>
<li><p><strong>Platform</strong>: The environment where V8 runs. For example, a browser has a different platform implementation than Node.js.</p>
</li>
<li><p><strong>Isolate</strong>: A memory-isolated instance of the V8 engine, designed to run untrusted JavaScript code.</p>
</li>
<li><p><strong>Handles</strong>: References to JavaScript objects. A <strong>HandleScope</strong> acts as a container for these handles, allowing the garbage collector to efficiently free memory.</p>
</li>
<li><p><strong>Context</strong>: The execution context, including global objects and variables, for JavaScript code.</p>
</li>
</ul>
<p>After initializing these components, the code is compiled and executed within the isolate.</p>
<p>One fascinating aspect of this process is the ability to expose custom runtime functionalities to the code running inside the isolate.</p>
<hr />
<h2 id="heading-expanding-the-rabbit-hole">Expanding the Rabbit Hole</h2>
<p>I also explored two articles that delve into building custom runtimes:</p>
<ol>
<li><p><a target="_blank" href="https://deno.com/blog/roll-your-own-javascript-runtime">“Roll Your Own JavaScript Runtime”</a> explains how to use <code>deno_core</code> to create a custom runtime.</p>
</li>
<li><p><a target="_blank" href="https://dzx.cz/2023-03-08/how_do_cloudflare_workers_work/">“How Do Cloudflare Workers Work?”</a> walks through creating a basic runtime with a single JavaScript function exposed to the isolate. Although the code is slightly outdated, it’s easy to adapt.</p>
</li>
</ol>
<p>These resources sparked new questions about the relationship between <strong>libuv</strong> (which powers Node.js’s async functionality) and V8, and how this differs from Deno's architecture—definitely something for another rabbit hole!</p>
<hr />
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>I know this series might not be polished or easy to read, and I’m still learning as I go. But sharing my notes helps me stay organized and serves as a reference for my future self.</p>
<p>If you’re curious about these topics or have insights to share, let me know! Until the next rabbit hole, happy exploring! 🐇</p>
]]></content:encoded></item></channel></rss>