<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Alessandro Romano on Medium]]></title>
        <description><![CDATA[Stories by Alessandro Romano on Medium]]></description>
        <link>https://medium.com/@alerom90?source=rss-c05915df6ba4------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*3daGIEkBQ_R8TDe8M3ULmg.jpeg</url>
            <title>Stories by Alessandro Romano on Medium</title>
            <link>https://medium.com/@alerom90?source=rss-c05915df6ba4------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 23 Jun 2026 13:55:15 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@alerom90/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[We Need More AI Educators And Fewer AI Influencers]]></title>
            <description><![CDATA[<div class="medium-feed-item"><p class="medium-feed-image"><a href="https://medium.com/design-bootcamp/were-surrounded-by-ai-influencers-6edf46bcbab0?source=rss-c05915df6ba4------2"><img src="https://cdn-images-1.medium.com/max/2600/0*eGWbGS9pwu1qhHvZ" width="3948"></a></p><p class="medium-feed-snippet">Where Did the Expert Engineers Go?</p><p class="medium-feed-link"><a href="https://medium.com/design-bootcamp/were-surrounded-by-ai-influencers-6edf46bcbab0?source=rss-c05915df6ba4------2">Continue reading on Bootcamp »</a></p></div>]]></description>
            <link>https://medium.com/design-bootcamp/were-surrounded-by-ai-influencers-6edf46bcbab0?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/6edf46bcbab0</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[public-speaking]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[computer-science]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Sun, 07 Jun 2026 19:17:57 GMT</pubDate>
            <atom:updated>2026-06-10T07:46:58.138Z</atom:updated>
        </item>
        <item>
            <title><![CDATA[The Lost Beauty of Code]]></title>
            <link>https://medium.com/design-bootcamp/the-lost-beauty-of-code-bb4a9b0855aa?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/bb4a9b0855aa</guid>
            <category><![CDATA[generative-ai-tools]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[future-of-work]]></category>
            <category><![CDATA[society]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Fri, 24 Oct 2025 11:12:24 GMT</pubDate>
            <atom:updated>2025-10-24T11:12:24.970Z</atom:updated>
            <content:encoded><![CDATA[<p><em>When code stops being written by humans, does beauty still matter?</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ddLuKvAnIG2zsQgO" /><figcaption>Photo by <a href="https://unsplash.com/@swimstaralex?utm_source=medium&amp;utm_medium=referral">Alexander Sinn</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>When I saw a quicksort for the first time, I was blown away. There was something almost poetic about it. A handful of lines that felt perfectly balanced, with no redundancy and no excess. Each instruction served a purpose, each line carried weight. It wasn’t just an algorithm; it was a composition. And the more I compared it with other sorting methods that were slower, heavier, and more wasteful in time or memory, the more I admired its purity.</p><h3>The Beauty in Simplicity</h3><p>Here’s the quicksort in <strong>C++</strong>:</p><pre>void quicksort(vector&lt;int&gt;&amp; arr, int left, int right) {<br>    int i = left, j = right;<br>    int pivot = arr[(left + right) / 2];<br>    while (i &lt;= j) {<br>        while (arr[i] &lt; pivot) i++;<br>        while (arr[j] &gt; pivot) j--;<br>        if (i &lt;= j) swap(arr[i++], arr[j--]);<br>    }<br>    if (left &lt; j) quicksort(arr, left, j);<br>    if (i &lt; right) quicksort(arr, i, right);<br>}</pre><p>It’s procedural and mechanical, yet there’s grace in how it moves data around a pivot, almost like choreography.</p><p>Now look at the same algorithm written in <strong>Haskell</strong>:</p><pre>quicksort :: (Ord a) =&gt; [a] -&gt; [a]<br>quicksort [] = []<br>quicksort (x:xs) = quicksort [a | a &lt;- xs, a &lt;= x]<br>                    ++ [x] ++<br>                    quicksort [a | a &lt;- xs, a &gt; x]</pre><p>This is minimalism at its finest. Recursive, declarative, effortless. It reads more like a definition of order than a process. <em>When I first saw it, I felt the same kind of satisfaction mathematicians feel when an equation suddenly makes sense.</em></p><p>For a long time, I was one of those who searched for that beauty, the kind that hides in the balance between logic, syntax, and purpose. Over time, that pursuit blended into what we now call best practices: clean code, readability, efficiency, and maintainability. But beneath all that structure, it was still about the same thing — the desire to make something that feels right.</p><h4><strong>The Era of Handcrafted Code</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s1a30Bqng9IHERd4n5kBkg.png" /><figcaption>Image generated by the Author with DALL-E</figcaption></figure><p>There was a time when programmers wrote code the way poets wrote verses. They obsessed over naming, indentation, and recursion. A single elegant line in Lisp or Python could make someone smile the way a good chord progression does. Reading code was an act of learning and admiration. Open-source projects weren’t just tools; they were living museums of style.</p><p>I remember leafing through <em>The Art of Computer Programming by Donald Knuth</em> and realizing that programming was never just about making machines work. It was about shaping ideas into logic, thinking clearly enough that a computer could understand you. Back then, you could tell who wrote a piece of code. It carried a signature, a voice.</p><p>Now, open a GitHub repository and ask yourself: could you tell if that code was written by a human or by a model? And would it even matter?</p><h4><strong>The Black Box Age</strong></h4><p>I can’t help but wonder what will happen to that sense of beauty when generative tools take over. If tomorrow’s code is written by models that don’t see or feel, where does elegance go? When the output becomes a black box — correct but opaque — who will care whether it’s beautiful?</p><p>It feels as though we’re discarding everything we used to value but couldn’t measure. If no human ever reads the code again, does readability still matter? If performance is optimized automatically, why think about memory allocation? And if the final result simply works, does anyone care how it got there?</p><p>While working on a Python package migration recently, I realized how much of our code was written the way it was not because it was faster, but because it was nicer. More elegant. Because somewhere along the way, programmers, myself included, started to think of themselves as artists. Yet when I ask Claude or other generative tools to refactor that code, they often struggle. They get the syntax right but miss the intent, the quiet reasoning that lives between lines. So what’s the real issue — that humans were fooling themselves, or that generative models still can’t grasp the deeper layers of human reasoning?</p><h4><strong>The New Relationship with Tools</strong></h4><p>Coding used to be about discovery. You started from a blank screen and built something piece by piece, debugging your way into understanding. Today, coding is more about selection. You prompt a model, get ten suggestions, and choose the one that feels right. Instead of asking “How do I build this?”, we now ask “Which of these generated solutions do I trust?”</p><p>This shift has changed how we learn. Debugging, once the best teacher of all, is slowly disappearing. You no longer need to trace through logic; you can just regenerate the whole block. The code works, but the understanding fades.</p><blockquote>For newcomers, this means they might never experience the joy of watching an algorithm unfold in their mind, of realizing why something works rather than just that it works. The act of thinking through code is being replaced by the act of curating it.</blockquote><h4><strong>When Machines Code for Machines</strong></h4><p>I often wonder who will win this quiet war: the models that will eventually learn to write like us, the code artists, or the programmers who will accept that beauty no longer matters as long as it runs. I use these tools every day. They’re astonishing, and they make my work faster. Yet I also work with exceptional engineers who still avoid them. I think part of that resistance comes from refusing to let go of the artistic part. Writing code used to mean leaving a trace of yourself behind — your taste, your discipline, your thought process. Now, it feels more like curating outputs from someone else’s brain.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Budoa7J-h4q8qe2Ow108QA.png" /><figcaption>Image created by the Author with DALL-E</figcaption></figure><p>This is not the same as AI-generated art or music, where the machine still creates for humans. Here, it’s machines writing for machines.</p><blockquote>We, the humans, just consume the final result: a working API, a web app, a dashboard. No more traces of elegance. No more code that feels like it was crafted.</blockquote><h4><strong>The Vanishing Craft</strong></h4><p>There’s another layer to this, one that reveals how fragile the system still is. If most new code is generated, what are we training these models on? On existing human code, yes, but also on a growing ocean of AI-generated code that may not carry human reasoning anymore. If that’s true, then beauty doesn’t just fade — it disappears by design. Because what the model learns next will be patterns of patterns, stripped of the original intent that shaped them.</p><p>And what happens when we face technical debt? A piece of code written long ago, deeply customized, obscure but efficient — will our smartest code-generation tools know what to do with it? Or will we need to hire one of those rare engineers who still speak that dialect of thought, like when banks had to call back retired COBOL programmers because no one else could read the code?</p><h4><strong>A Glimpse of What Might Survive</strong></h4><p>Maybe beauty isn’t dying. Maybe it’s just moving. Perhaps in the future, elegance will live not in the lines of code but in the interaction between humans and machines, in how we phrase prompts, orchestrate agents, or define logic at higher levels of abstraction. Maybe we’ll start admiring a different kind of clarity — the ability to translate human intent into machine reasoning with precision and empathy.</p><p>That could be our new art form. Prompt design as poetry. System architecture as composition. Flow design as storytelling. It’s not the same beauty we grew up with, the kind you could read line by line, but it might still be a kind of craftsmanship. One that belongs to the hybrid world we’re building.</p><h3><strong>Epilogue: Beauty as a Byproduct</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TFOLXifnAxFwlsBoOth5bA.png" /><figcaption>Image created by the Author with DALL-E</figcaption></figure><blockquote>Maybe that’s the irony. We once built beauty into code because we had to see it. Soon, we might build code we can’t even see at all.</blockquote><p>And yet, I still believe there was something valuable in that pursuit — not because it made the software better, but because it made us better. It taught us to care about structure, to respect logic, to find harmony between chaos and order. It reminded us that behind every function, there was once a human hand, trying to make something work, and trying, just a little, to make it beautiful.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bb4a9b0855aa" width="1" height="1" alt=""><hr><p><a href="https://medium.com/design-bootcamp/the-lost-beauty-of-code-bb4a9b0855aa">The Lost Beauty of Code</a> was originally published in <a href="https://medium.com/design-bootcamp">Bootcamp</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Glove80 Keyboard Review: Why It’s the Best Ergonomic Keyboard I’ve Ever Used]]></title>
            <link>https://medium.com/design-bootcamp/glove80-keyboard-review-why-its-the-best-ergonomic-keyboard-i-ve-ever-used-d13b91e7318e?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/d13b91e7318e</guid>
            <category><![CDATA[ergonomics]]></category>
            <category><![CDATA[split-keyboards]]></category>
            <category><![CDATA[keyboard]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[coding]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Sat, 16 Aug 2025 14:36:12 GMT</pubDate>
            <atom:updated>2025-08-16T16:44:35.945Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jhtVVGMKQkGySwo8JNb-jQ.png" /><figcaption>Generated with DALL-E</figcaption></figure><p>If you’re looking for advice on an ergonomic keyboard, you can stop at the title. This isn’t clickbait, and there are no plot twists here. What I want to share is something I wish I had read a few years ago, back when I was searching for ways to improve my typing comfort and posture at the laptop.</p><p>I see a lot of “keyboard experts” out there who know every switch ever made, sorted by color, weight, and sound profile. I’m not one of them. And that’s exactly why I’m writing this: because when I was in your position, I would have loved to hear from someone like me.</p><p>This article is for people who simply want to know what it takes to find <em>their</em> keyboard and what it should feel like. For me, that keyboard is the <a href="https://www.moergo.com/?srsltid=AfmBOoo-si9mWsWvFy_kHZEf9VlX7PJgHpdkeAX29qIGR1uRvL2xoS5A"><strong>Glove80</strong></a>, which I first mentioned in another piece. Will it be the same for you? Hopefully, my long-term experience helps you figure that out.</p><h3>First Impressions</h3><p>I’ve always been proud of my touch typing skills. I’m probably just above average, but as a software engineer, it’s something I rely on daily. That’s why I was afraid of having to relearn everything from scratch on a split ergonomic keyboard. I was wrong.</p><h4>Real Ergonomics</h4><p>The first time I placed my hands on the Glove80, I felt a level of relaxation I had never experienced before at the keyboard. I was not fast, and I had to adapt, but the important part was that my wrists were no longer tense. That tension you feel when you need to lift your fingers unnaturally to match the key height — it was gone.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2Ar_eEz3qBEMY5uwHPODfw.jpeg" /><figcaption>How the design accomodates the shape of your hand — Image from the Author</figcaption></figure><p>If you have tried a low-profile keyboard, you know what I mean. But the Glove80 takes it a step further. The curved layout combines the comfort of low-profile keys with genuine ergonomic shaping. I remember resting my hands on the board, positioning my fingers, and then lifting my arm as if it were frozen in place. That demonstrated just how naturally the Glove80 was following the shape of my hands, accommodating them without effort.</p><h4>Look Mom, I can Type Numbers!</h4><p>The curvature allows you to reach the number row naturally. And here is my question to keyboard manufacturers: why should I need a layer just to type numbers? Why has the number row become some sort of forbidden luxury, as if having one makes you uncool and means you deserve to type on needles?</p><p>Let me be clear: I use layers, but I also use the number row, and even the F keys. Yes, the F keys. Because the Glove80 has them, and I can reach them easily without moving my palms.</p><h4>It’s wireless and it just works</h4><p>This was one of the first things I noticed. With other keyboards, reliable wireless was never guaranteed. Some companies even told me, “We’re still working on it — wireless is tricky.” Sure, but charging €500 for a keyboard that constantly disconnects seems even trickier.</p><p>The Glove80 simply works. You have two units that connect to your laptop, and they never disconnect. Not once during the last year. Being amazed by something so basic in 2023 felt strange, but that is the reality.</p><h3>After One Year</h3><p>I have grown as a user. I no longer make jokes about other ergonomic keyboard companies, and I love my Glove80 even more than at the beginning.</p><p>It is time to dive into the details — what I like and what I don’t. The balance is very positive, of course. If I had to buy another keyboard tomorrow, I would not hesitate. But the full picture is more complex than that, and some of the details might play a big role if you are about to make your own buying decision.</p><h4>Type with your Fingers, not Wrist or Shoulders</h4><p>This is the best way I can describe the difference. I no longer use my wrists or shoulders to type — they stay relaxed. The two design choices that make this possible are:</p><ol><li>The split layout allows you to open your chest and position the halves wherever you like.</li><li>The natural curvature created by the palm rest and the keys lets your hands fall into place without tension.</li></ol><p>The natural tilt, which you can adjust further if you like, also gives you a powerful customization option.</p><p>These three aspects already create a big improvement. Some of them can be found in other great ergonomic boards, like the ErgoDox. But combined with the Glove80’s unique curvature, the feeling is one of a kind.</p><h4>Thumbs and Pinkies found their vocation</h4><p>By now, it’s almost common knowledge that the thumb can do more than just hit the spacebar, and that the pinky shouldn’t be forced to stretch to unreachable places. Most ergonomic keyboards try to address this, but the real difference is in <em>how</em> you implement it — and that’s where the experience can make or break the design.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/730/1*xdPFqI8hUxFCI58dRGlLtg.gif" /><figcaption>You can easily reach the thumb keys — Image from the Author</figcaption></figure><p>I had a hard time adapting to the thumb cluster on the Dygma Defy. It looked powerful, but in practice I often felt frustrated. You don’t need to reach every single thumb key, but the most important ones should always be in a position that feels natural. More than one year later with the Glove80, I can confidently say they nailed it. The thumb keys are placed at slightly different levels, easy to reach without any awkward movements. Once again, you don’t have to use them all the time, and it’s fine if some remain “secondary,” but the main ones are right there where you want them. The simplicity of the design is what makes it so effective.</p><p>On the other hand, my pinkies are finally resting. The whole point of relying more on the thumbs is to avoid stretching your hand, so the pinky doesn’t have to do the heavy lifting. And the Glove80 goes further: the outer columns are designed at different heights because pinkies are shorter. That detail alone makes typing so much more satisfying. It’s not only true for the pinky — each finger has its own natural height, and the staggered column design respects that anatomy. Resting my fingers there feels effortless, and over time it became one of the most convincing aspects of this keyboard’s ergonomics.</p><h4>The Unexpected</h4><p>Some features only revealed themselves after long use:</p><ul><li><strong>Form factor</strong>: carrying it to the office is not great. I do not use the official case (too big), so I just wrap the halves together. It works, but it is not elegant. I wish there were a slim protective cover, like the ones you see for portable synths.</li><li><strong>Layers</strong>: I use them far less than expected. With a nearly full layout, layers are only for shortcuts and coding extras.</li><li><strong>Tilting</strong>: I do not use the extra tilting mechanism. The natural tilt is enough for me.</li><li><strong>Arrow keys</strong>: I use them constantly, especially for coding, and their placement is excellent. I was skeptical at first, but now I cannot live without it.</li><li><strong>Materials</strong>: Yes, it is plastic. At first, I missed the premium feel of aluminum keyboards, but the plastic allows the Glove80 to achieve its ergonomic shape. The board is solid and well-built, and that is all that matters.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Xg68mOf_op6fnYNPZP3EgQ.jpeg" /><figcaption>The arrow keys have their perfect spot — Image from the Author</figcaption></figure><h4>The Final Upgrade</h4><p>One limitation of the Glove80, which for some is a downside and for others a feature, is that the switches are not hot-swappable. This design choice allows for a very low profile that keeps your hands closer to the desk, which is fantastic ergonomically. But it also means that if one day you want to upgrade or change the feel, you need the skills (and patience) to desolder components.</p><p>For me, this was not really a problem. I was happy with my initial choice of switches: <strong>Kailh Choc v1 Red Pro Linear 35gf</strong>. I liked them at first, but after a long while — thousands of words typed — I started to notice they felt a bit wobbly. This wasn’t something obvious in the beginning. It took me almost a year of daily use before I realized it. It was just a subtle feeling that grew over time: “These switches could be more stable.”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2Ge8rCzHsmXlyonCl5qSvg.jpeg" /><figcaption>Installing the new Blossom Switches — Image from the Author</figcaption></figure><p>Then the <a href="https://www.moergo.com/collections/choc-v1-key-switches"><strong>Blossom</strong></a><strong> switches</strong> came out, a brand-new switch designed exclusively for the Glove80. And suddenly, everything I had disliked about the Red Pro Linears was addressed.</p><p>Here is the problem, though: I am not a switch nerd. It took me a long time to even evaluate my Reds honestly. And the thought of pulling out a soldering iron, desoldering dozens of switches, and risking damage to a keyboard I rely on every day was terrifying. I didn’t want to accidentally burn the PCB in the process.</p><p>The company thought of this, and that is where they truly impressed me: you can actually buy only part of the keyboard with the new switches already mounted. The upgrade becomes effortless — you just replace that section, and you’re done. No soldering nightmare, no risk, no wasted hours.</p><p>And the difference? Remarkable. The Blossoms are very quiet, perfectly stable, and provide just the right balance of resistance and feedback. No wobbling. No accidental presses. You can rest your fingers on the keys without triggering them. When I type in the office or during calls, the low noise is a blessing. The soft sound feedback is still there, but it is subtle enough not to disturb anyone.</p><p>This upgrade brought my Glove80 to a new level. For the first time, I felt what it meant to have the <em>right</em> switches under my fingers — silent when needed, solid under pressure, and precise with every stroke. It may come down to personal taste, and of course gaming needs are different, but unless you are chasing a very specific feel, it’s hard to imagine anyone disliking the Blossom switches.</p><h4>What’s Egonomic and What’s not?</h4><p>I am not a switch nerd, but I have become an ergonomics nerd. My approach is simple: listen to both your body and the science. Comfort does not always equal ergonomics, and ergonomics on paper does not always work for everyone.</p><p>Think of a bike saddle. A soft, wide saddle feels great at first, but it often puts pressure in places that should not be under pressure. A harder, narrower saddle may actually be healthier. Keyboards are similar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eQPpfZkMntY8eGGbCS59Qw.png" /><figcaption>Generated with DALL-E</figcaption></figure><p>In my opinion, the Glove80 is a genuinely ergonomic keyboard. It is not just about splitting the layout to open your shoulders. It is a design built around the hand. It will not be perfect for everyone, but for most people it will be a revelation. I compare it to the Aeron chair by Herman Miller: a design so well thought out that it remains a benchmark even years later.</p><h3>Conclusions</h3><p>If you are searching for a keyboard and what I described resonates with you, I honestly recommend giving the Glove80 a try. Do not expect instant magic—if you are coming from a standard laptop or mechanical keyboard, you will need a little time to adjust. But once your hands settle in, it becomes very hard to imagine going back.</p><p>After more than one year, and even after a major switch upgrade, the Glove80 remains my daily driver. I’ve experimented with other products, and I had fun doing it, but nothing has matched the combination of comfort, practicality, and sheer “rightness” that this board delivers.</p><p>For me, it is more than just another keyboard. It’s a tool that quietly reshaped the way I type, the way my hands and shoulders feel after hours of work, and even the way I think about ergonomics in general.</p><p>Will it be perfect for everyone? Probably not. Ergonomics is deeply personal. But like the Aeron chair in the world of office seating, the Glove80 represents a design that is hard to beat once you understand what it offers.</p><p>So if you are still undecided, my advice is simple: invest the time, try it, and let your body decide. Chances are, you’ll end up—like me—wondering how you ever typed differently.</p><p><a href="https://medium.com/design-bootcamp/do-you-need-an-ergonomic-keyboard-70c5fe1a4ffe">In the meantime, check out my previous article about my journey into the world of ergonomic keyboards.</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d13b91e7318e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/design-bootcamp/glove80-keyboard-review-why-its-the-best-ergonomic-keyboard-i-ve-ever-used-d13b91e7318e">Glove80 Keyboard Review: Why It’s the Best Ergonomic Keyboard I’ve Ever Used</a> was originally published in <a href="https://medium.com/design-bootcamp">Bootcamp</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[I Fine-Tuned an LLM on 5 Years of Telegram Chats]]></title>
            <link>https://medium.com/data-science-collective/i-fine-tuned-an-llm-on-5-years-of-telegram-chats-7bacb66387c8?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/7bacb66387c8</guid>
            <category><![CDATA[telegram]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[fine-tuning]]></category>
            <category><![CDATA[bots]]></category>
            <category><![CDATA[hugging-face]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Tue, 13 May 2025 02:57:19 GMT</pubDate>
            <atom:updated>2025-05-13T02:57:19.691Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*B1WUjlg7O3-2gZGI" /><figcaption>Photo by <a href="https://unsplash.com/@sigmund?utm_source=medium&amp;utm_medium=referral">Sigmund</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Experimenting with Telegram has always been one of my favorite ways to test new algorithms, tools, and libraries. <a href="https://alerom90.medium.com/how-i-made-my-girlfriend-happy-with-a-simple-telegram-bot-2be8e4b150e7">A few years ago I even wrote an article about one of those early attempts</a>. One idea that stuck with me over time was the challenge of creating a digital version of myself, a chatbot that could handle simple conversations in my style without needing my input. Not because I needed it, but simply because the concept fascinated me.</p><p>Years ago I tried building this using LSTM and Seq2Seq models, but I gave up quickly. The training was painful, the loss curve erratic, and I realized that <a href="https://arxiv.org/abs/1706.03762">attention is all I needed</a>.</p><p>Now that fine-tuning LLMs is becoming more accessible, I decided to revisit the project. The goal is to build a chatbot that responds like me, with my tone and personality. The main goal of this article is to share what I learned from the experience, not just the technical details of fine-tuning an LLM with LoRA, which are already well-documented elsewhere. I’ll also make the code available for anyone interested in trying it out.</p><h3>Approach Overview</h3><p>The steps are fairly intuitive if you have a basic understanding of data science or machine learning. I start by preparing the data, then choose a model that fits my needs, decide where to run it, and finally test the whole setup.</p><h4>The Training Set</h4><p>I’m using five years of messages from a group chat with five people, myself included. It’s probably the chat I use the most. I don’t spend much time texting overall, so this is the best dataset I have. If I had to summarize the content of this chat, it would be:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4JnItkNBqvZtpUhmko7Zog.png" /><figcaption>Image created by the Author with DALL-E</figcaption></figure><p>Getting the data wasn’t a big deal — I just downloaded the HTML export from Telegram Lite. The annoying part was parsing it into a usable format, like this:</p><ul><li><strong>Prompt</strong>: A block of chat history, including both <em>User</em> and <em>Assistant</em> messages, leading up to a new expected response. It provides the context needed for the model to generate a coherent reply.</li><li><strong>Response</strong>: The assistant’s expected next reply based on the full prompt above.</li></ul><pre>{<br>  &quot;prompt&quot;: &quot;User: Feel like playing COD tonight? I want to go skydiving. Might be out all week. Tough days. Maybe Damacco is right, maybe we should sell the PlayStations... I&#39;m starting to see the world through his eyes. PS5, headset, all in. Download Helldivers instead of complaining.&quot;,<br>  &quot;response&quot;: &quot;Hahaha&quot;<br>}<br>{<br>  &quot;prompt&quot;: &quot;User: Feel like playing COD tonight? I want to go skydiving... Download Helldivers instead of complaining.\nAssistant: Hahaha&quot;,<br>  &quot;response&quot;: &quot;Skydiving over a landfill. 360 cam (can’t wear it before 200 jumps). You toss stuff from the plane.&quot;<br>}<br>{<br>  &quot;prompt&quot;: &quot;User: Skydiving over a landfill. 360 cam (can’t wear it before 200 jumps). You toss stuff from the plane.\nAssistant: Toss stuff from the plane, great idea. Someone who can afford the premium will catch it.&quot;,<br>  &quot;response&quot;: &quot;Now jumps are a currency. How many jumps does it cost?&quot;<br>}<br>{<br>  &quot;prompt&quot;: &quot;User: Now jumps are a currency. How many jumps does it cost?\nAssistant: Toss stuff from the plane, great idea. Someone who can afford the premium will catch it.&quot;,<br>  &quot;response&quot;: &quot;We can’t play with someone ready to sell their PS5. It&#39;s not fair to the founding fathers.&quot;<br>}</pre><p>If the assistant (me) replies multiple times during the conversation, each reply becomes a new entry in the dataset with its own prompt-response pair. This means that a single discussion can generate multiple JSON lines, each representing one assistant turn, with growing context.</p><p>The reason behind this structure is that I want the LLM to grasp the context of an ongoing discussion. A chat-like format is essential for teaching the model how conversations naturally flow.</p><h4>Choosing The Model</h4><p>The place to start is Hugging Face, there you can choose between the smallest model up to the one with the one with billion of parameters. My choice fall on <a href="https://huggingface.co/TinyLlama/TinyLlama-1.1B-Chat-v1.0">TinyLLama</a> and <a href="https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.3">Mistral-7B-Instruct-3.0</a>. I identified them as good choice considering that I only need a model has the basic info of the language in order to “speak”. Also, bigger models require bigger GPU, hence more money.</p><p>Having a model already trained is what you want, because we are going to use LoRA (Low-Rank Adaptation), a lightweight method where only a small number of parameters are added and trained, while the original model stays frozen. It makes fine-tuning large models faster, cheaper, and more memory-efficient.</p><blockquote>You can think of this step like training an actor to follow a script closely, so they can fully embody a specific character and behave just like them.</blockquote><h4>Hardware</h4><p>To fine-tune an LLM (or train one from scratch), you need access to a GPU. The easiest way to get that is through a cloud service. Depending on the model size, you can choose between:</p><ul><li><strong>NVIDIA L4 (Ada Lovelace Tensor Core)</strong> — Suitable for TinyLlama and possibly for Mistral 7B, though it struggles with the latter due to its parameter size.</li><li><strong>NVIDIA A100 Tensor Core</strong> — A much more powerful and reliable option, ideal for models like Mistral 7B.</li></ul><p>The cost is roughly $0.40/hour for the L4 and $1.70/hour for the A100 — not bad when you consider that the A100 alone costs over $20,000.</p><p>Both are available on Google Colab, but I ended up using RunPod, after having my notebook disconnected multiple times on Colab.</p><h3>Outcome and Learnings</h3><p>Here I’ll walk through what worked as expected and what didn’t. Most of these insights came from actually training and testing the model, which meant going through fine-tuning sessions of at least 3 hours each — given that I was using a training set of at least 30,000 samples.</p><h4>The Model doesn’t Like Bad Jokes</h4><p>At this point in the process, I saw a sharp spike in the training loss (from 2 till 22) — basically enough to invalidate the fine-tuning. I inspected the samples that triggered it, and at first glance, everything looked normal. But then I realized the entire thread was a series of dark humor jokes about a Call of Duty match. After digging deeper, I found that Instruct models are trained to be polite and helpful, and they often resist learning patterns that go against those guidelines. That includes humor styles that may be considered inappropriate or offensive, which likely caused the instability. The solution was to use <a href="https://huggingface.co/mistralai/Mistral-7B-v0.1"><em>mistralai/Mistral-7B-v0.1</em></a><em>.</em></p><h4>Fine-Tuning With LoRA</h4><p><a href="https://huggingface.co/docs/peft/main/en/conceptual_guides/lora">LoRA</a> is a method that fine-tunes large language models efficiently by injecting small trainable matrices into the model’s existing layers — typically the attention or feedforward layers. Instead of updating all parameters, LoRA freezes the original model and only trains these low-rank matrices, drastically reducing the number of trainable parameters:</p><ol><li><strong>Faster training</strong></li><li><strong>Much lower GPU memory usage</strong></li><li><strong>You can easily switch between multiple fine-tuned versions</strong></li></ol><p>In short, <strong>LoRA lets you adapt big models with small compute</strong>. Here a quick overview of what I used for my configuration:</p><pre># 1. Prepare quantized model for LoRA<br>model = prepare_model_for_kbit_training(model)<br><br># 2. Define LoRA configuration<br>lora_config = LoraConfig(<br>    r=16,<br>    lora_alpha=32,<br>    target_modules=[&quot;q_proj&quot;, &quot;v_proj&quot;],<br>    lora_dropout=0.05,<br>    bias=&quot;none&quot;,<br>    task_type=TaskType.CAUSAL_LM,<br>)<br><br># 3. Wrap model with LoRA<br>model = get_peft_model(model, lora_config)</pre><p>Among the LoRA parameters, two are particularly worth highlighting, which helped me to steer the training a bit:</p><ul><li><strong>r</strong>: This sets the rank of the low-rank matrices injected into the model. A higher r allows the model to adapt more, but also increases memory and training cost. It&#39;s the main lever for balancing performance and efficiency.</li><li><strong>lora_dropout</strong>: Dropout applied only within the LoRA layers during training. It helps regularize the fine-tuning process and avoid overfitting, which is especially useful when working with small or noisy datasets like personal chat logs.</li></ul><p>In the training configuration, I used a learning rate of 2e-4, which balanced speed and stability. Enabling fp16 reduced memory use and sped up training. With a batch size of 4 and gradient_accumulation_steps=2, I could simulate a larger batch on limited GPU memory. warmup_steps=50 helped avoid instability at the start.</p><pre>training_args = TrainingArguments(<br>    output_dir=MISTRAL_OUTPUT,<br>    per_device_train_batch_size=4,<br>    gradient_accumulation_steps=4,<br>    num_train_epochs=3,<br>    logging_steps=50,<br>    save_steps=500,<br>    save_total_limit=2,<br>    learning_rate=2e-4,<br>    fp16=False,<br>    bf16=True,<br>    report_to=&quot;none&quot;<br>)</pre><h4>Tokenization</h4><p>Tokenization is the process of converting text into smaller pieces — called tokens — that a model can understand. These tokens can be words, subwords, or even characters, depending on the tokenizer. I did this wrong a couple of times, which impacted my training very bad, till I implemented this:</p><pre>def load_jsonl(path):<br>    with open(path, &quot;r&quot;, encoding=&quot;utf-8&quot;) as f:<br>        lines = [eval(line) for line in f]<br>    return Dataset.from_list(lines)<br><br>dataset = load_jsonl(DATA_PATH)<br><br>def tokenize(example):<br>    full_input = example[&quot;prompt&quot;] + example[&quot;response&quot;]<br>    input_ids = tokenizer(<br>        full_input,<br>        truncation=True,<br>        padding=&quot;max_length&quot;,<br>        max_length=512<br>    )[&quot;input_ids&quot;]<br><br>    # Mask everything except the response<br>    prompt_ids = tokenizer(example[&quot;prompt&quot;], truncation=True, max_length=512)[&quot;input_ids&quot;]<br>    labels = [-100] * len(prompt_ids) + input_ids[len(prompt_ids):]<br>    labels = labels[:512]  # truncate again to ensure it&#39;s the same length<br>    input_ids = input_ids[:512]<br><br>    return {<br>        &quot;input_ids&quot;: input_ids,<br>        &quot;labels&quot;: labels,<br>        &quot;attention_mask&quot;: [1] * len(input_ids)<br>    }<br><br>tokenized_dataset = dataset.map(tokenize, batched=False)</pre><p>Once the dataset is ready, the next step is to tokenize it — that is, to convert text into a format the model can understand. Each example in my dataset is a conversation snippet with a <em>prompt</em> (what the user said or what was already said in the chat) and a <em>response</em> (what the assistant or bot should say next).</p><p>Instead of training the model to learn both the prompt and the response, I want it to learn only <strong>how to reply</strong>. To do this, I concatenate the prompt and the response into one sequence of tokens, but I apply a trick: I <strong>mask out</strong> the prompt part in the labels using -100. This tells the model: <em>“Don&#39;t try to learn this part—just focus on predicting the response.”</em></p><p>Here’s what happens for each message:</p><ul><li>The full text (prompt + response) is tokenized into input IDs.</li><li>The prompt tokens are replaced with -100 in the labels so they are ignored during training.</li><li>The rest (i.e., the response) is left as-is, so the model learns to generate it.</li></ul><p>This simple trick helps the model learn to respond in the right tone and context, without wasting compute trying to reproduce the prompt.</p><h4>Inference</h4><p>Once fine-tuning is complete, only the <strong>LoRA adapter parameters</strong> are saved — not the entire model. This makes storage and deployment much lighter. After that, I moved on to the inference phase to test the results.</p><p>The performance of <strong>TinyLlama</strong> was disappointing. It struggled to capture my tone and often produced hallucinated outputs that barely resembled real language. This was likely due to the model’s small size, combined with the sarcastic tone and absurd threads typical of the chat. The subtlety and context required were simply too much for such a lightweight model.</p><p>On the other hand, <strong>Mistral 7B</strong> delivered great results. It was able to pick up on recurring jokes, nicknames, and even subtle patterns in how we talk. By adjusting the model’s <strong>temperature</strong>, I could control the creativity of the responses — lower values made it more predictable, while slightly higher ones brought out a more natural and playful tone, helping generate conversations that actually felt real.</p><pre>prompt = (<br>    &quot;User: Up for a match?\n&quot;<br>)<br>input_ids = tokenizer(prompt, return_tensors=&quot;pt&quot;).input_ids.to(model.device)<br><br>output = model.generate(<br>    input_ids=input_ids,<br>    max_new_tokens=50,<br>    do_sample=True,<br>    temperature=0.7,<br>    top_p=0.8,<br>    pad_token_id=tokenizer.eos_token_id  # avoids warning<br>)<br><br>print(tokenizer.decode(output[0], skip_special_tokens=True))</pre><p>Of course, this kind of model doesn’t know when to stop on its own, so you need to set a limit using max_new_tokens. This caps the number of tokens the model can generate in a single reply, preventing endless or overly long outputs.</p><h4>More Data Cleaning</h4><p>After testing the bot, I noticed several responses like this one:</p><pre>{<br>  &quot;prompt&quot;: &quot;User: Do you have plans for tomorrow?&quot;,<br>  &quot;response&quot;: &quot;3:47 PM.&quot;<br>}</pre><p>The model was often replying with just a time, even when the question had nothing to do with scheduling. That’s when I realized a large portion of my training data came from coordinating gaming sessions, where I frequently responded with a time — like “What time are you guys online today?”. These replies were overrepresented in the dataset, and only after fine-tuning did I realize they were skewing the model’s behavior. In hindsight, I should have filtered or balanced these examples beforehand.</p><p>A good rule of thumb when preparing the data is to preserve as much as possible to capture your tone and personality. However, you’re also responsible for deciding what behaviors are worth replicating. If your dataset includes a lot of one-word replies like times, you have to ask yourself — Do I really want my bot to answer that way?</p><h3>Conclusions</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/973/1*ycEB_Kf4U3Cge6aeqmICsQ.jpeg" /><figcaption>Image from the Author</figcaption></figure><p>Am I happy with the results? I’d say yes — mainly because I didn’t start with clear expectations. The original goal was to replicate my tone, but I ended up genuinely enjoying the process, especially reading the generated conversations! Some of them were so absurd and spot-on that it felt like chatting with a distorted, funhouse-mirror version of myself. Here’s an example:</p><pre>User: Are we playing tonight or are we selling everything and retiring?<br><br>Assistant: Selling everything. PS5, headset, honor. Out the window.<br>User: Even the Helldivers save file?<br>Assistant: Especially the Helldivers save file. We’re free now.<br>User: So... 9:30?<br>Assistant: 9:47. Precision is a mindset.<br>User: You&#39;re starting to sound like Antony.<br>Assistant: I&#39;ve uploaded his personality. It cost me 14 jumps.</pre><p>In this example, the input was a sentence from the user that mirrors how we normally talk in the chat. The assistant’s reply is surprisingly good — it includes references to things I’ve actually said, mixed with the kind of nonsense that’s typical of our conversations. The tricky part with replies like <em>“It cost me 14 jumps”</em> is that I can’t always tell if it’s pulling from real inside jokes in the data, or if it’s just the LLM hallucinating. Then again, that might be the point. Maybe I sound like a hallucinated LLM in real life — and that’s why it works.</p><p>The total cost of the project was around $70, mostly spent on running the NVIDIA A100. In one of my later training sessions, I decided to shorten the chat threads and use only one year of data. This increased the number of training samples and, interestingly, turned out to be the most successful run. My guess is that shorter, more focused conversations made it easier for the model to understand the context of my replies. With less noise and tighter inputs, the attention mechanism could more effectively focus on the relevant parts of each interaction.</p><p>This brings me to the next step: running another fine-tuning round using the full dataset. Hopefully, this time RunPod won’t crash mid-training, as it occasionally did during earlier runs. Now I’m starting to wonder… is there a cloud provider I can actually trust? 🙂</p><p>Here is the link to the notebooks I used for training and inference, which will probably be converted into a GitHub repo in the near future:</p><ul><li><a href="https://colab.research.google.com/drive/1Qfxui7XtuzbEMrUTB1uJTiL0-RvWDix3?usp=sharing">Google Colab</a></li><li><a href="https://colab.research.google.com/drive/1y_AWskwKDMAGWWMKompnW8QDOnRUbZ7_?usp=sharing">Google Colab</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7bacb66387c8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science-collective/i-fine-tuned-an-llm-on-5-years-of-telegram-chats-7bacb66387c8">I Fine-Tuned an LLM on 5 Years of Telegram Chats</a> was originally published in <a href="https://medium.com/data-science-collective">Data Science Collective</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why Are We All Talking About AI Agents?]]></title>
            <link>https://medium.com/design-bootcamp/why-are-we-all-talking-about-ai-agents-68405dd9217a?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/68405dd9217a</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[agentic-ai]]></category>
            <category><![CDATA[llm]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Sun, 13 Apr 2025 13:25:44 GMT</pubDate>
            <atom:updated>2025-04-13T13:25:44.294Z</atom:updated>
            <content:encoded><![CDATA[<h3>Why are we all talking about AI Agents?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7i1PMEqrzA-B1v_W" /><figcaption>Photo by <a href="https://unsplash.com/@dnevozhai?utm_source=medium&amp;utm_medium=referral">Denys Nevozhai</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>As a data scientist immersed in daily tasks and deep into the hottest topics of the past decade, I sometimes forget how overwhelming AI can feel to those outside my professional bubble. I’m reminded of that famous infographic showing how much data we generate every second — the so-called “big data” era. And yet, while some are still trying to grasp what big data even means, data scientists are already calling things like RAG “old news.”</p><p>During my recent talk at a conference in Warsaw, the audience reminded me just how curious and eager people are to understand what an “agent” even is. That moment woke me up (again) to the fact that being a data advocate comes with responsibilities 🙂</p><p>In this post, I want to walk you through a few key concepts that will help you feel more confident whenever the topic of AI Agents comes up, and hopefully give you the tools to start thinking about how you might design solutions using them.</p><h3>Minimum Requirements</h3><p>The term <em>agent</em> refers to an entity capable of taking actions within a specific environment and under certain constraints. Of all the things we’ll discuss, this is the most important. Without this ability to act purposefully within a defined context, in my opinion, we’re not really talking about agents.</p><h4>Environment</h4><p>Why is this so crucial? Because an agent operates within a world governed by rules, a structured environment, its goal is to achieve something <em>within</em> those boundaries.</p><p>Imagine a person trying to get from point A to point B on foot. To reach their destination, they must follow a certain path, cross streets, wait for traffic, obey the laws of physics, and respect traffic rules. The environment defines the constraints and conditions under which the agent operates.</p><h4>Actions</h4><p>The agent interacts with the environment through a set of predefined actions. In our example, walking is one such action. Teleporting, on the other hand, probably isn’t allowed (yet!). These actions define <em>how</em> the agent can respond to or influence the environment, they form the interface between the agent and the world around it.</p><h4>Tools</h4><p>A few years ago, I would’ve considered tools just another kind of action. But over time, “tools” have become a widely accepted concept, often discussed in the context of agents.</p><p>Tools are resources the agent can use to perform its actions more effectively. For instance, instead of walking from point A to B, the agent might choose to ride a bike or drive a car. The action is still “move,” but the tool used dramatically affects how that action plays out.</p><h3>LLM Agents</h3><p>If you’ve ever implemented an agent based on the principles above, you’ve probably come to the conclusion that letting such a complex and unpredictable “creature” roam freely in the real world could be… problematic.</p><p>Even the best-designed set of instructions can break down in the face of the countless things that can go wrong on the way from point A to point B: construction sites, accidents, strikes, other agents — the list goes on.</p><h4>Dynamic Environments</h4><p>The biggest challenge is dealing with <strong>dynamic environments</strong>. It’s like when you take your first machine learning course and classify Titanic passengers by survival rate, then later access a real production database and realize that life is far messier than you thought.</p><p>When agents operate in fast-changing environments, where the rules are only partially known or constantly shifting, we need more than static instructions. We need a better way to help them <em>adapt</em>.</p><h4>Implementing Reasoning</h4><p>With the rise of large language models (LLMs), the conversation around agents has resurfaced (after years of being a niche topic reserved for experts). Just like NLP was mostly overlooked by the mainstream until ChatGPT arrived, agents have come back into focus with new energy.</p><blockquote>And here’s where a pivotal shift happened:<br><strong>What if we used the LLM as the reasoning engine inside the agent?</strong></blockquote><p>This idea changed the game. Suddenly, agents were no longer confined to deterministic logic. They could navigate uncertainty, ambiguity, and complex goals. The LLM became the core component that allows agents to decide what action to take next, which tool to use, whether the output is “good enough,” or whether more steps are needed.</p><h4>How Do We Reason?</h4><p>Of course, calling this <em>reasoning</em> raises eyebrows. Some people object to the term, arguing it anthropomorphizes machines or oversells their capabilities. I get that — and it’s a fair concern.</p><blockquote>But I like to challenge that view by asking:<br><strong>How can we claim this <em>isn’t</em> reasoning, when we don’t even fully understand how <em>we</em>, as humans, reason?</strong></blockquote><p>Sure, it’s a stretch — maybe even a provocation — but it gets the point across. What matters is that we’ve built a system that can make contextual decisions, evaluate outcomes, and adapt to changing goals. Whether or not we call that reasoning is, in the end, just semantics.</p><h3>Why go from A to B?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tbx7kYPz57rVaa2V" /><figcaption>Photo by <a href="https://unsplash.com/@lulusphotography?utm_source=medium&amp;utm_medium=referral">Luemen Rutkowski</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>In this typhoon of new terminologies and frameworks (seriously, stop sending me emails! I don’t want to try your “cutting-edge, production-ready agent platform”), the truth is that, once again, marketing teams are two steps ahead of engineering. They’re selling technologies that barely exist, and then scrambling to come up with actual use cases to justify them.</p><p>And for the record, I’m not even complaining. It is what it is. That’s exactly why I’m writing this article 🙂</p><p>So maybe the real question isn’t <em>how</em> to get from point A to point B using agents — but rather: <strong>do we even need to go from A to B?</strong> Only then does it make sense to ask whether an agentic AI application is the right tool for the job.</p><h3>Conclusions</h3><p>Now I can finally answer the question in the title: <strong>Why is everyone suddenly talking about AI Agents?</strong></p><blockquote>Because with the rise of LLMs, agents can now reason through complex, ever-changing environments — tackling a specific class of problems that can’t be solved with deterministic rules alone.</blockquote><p>If you want to see a practical example, <a href="https://youtu.be/I98l3wLJ5Oo?si=_Ogx60cdFb9ihG2J">check out one of my recent talks</a>, where I explain how I used a simple Python + CrewAI application to plan a ski trip. It’s a fun, real-world case of how agents can actually help.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=68405dd9217a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/design-bootcamp/why-are-we-all-talking-about-ai-agents-68405dd9217a">Why Are We All Talking About AI Agents?</a> was originally published in <a href="https://medium.com/design-bootcamp">Bootcamp</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Implement Guardrails for Your AI Agents with CrewAI]]></title>
            <link>https://medium.com/data-science/how-to-implement-guardrails-for-your-ai-agents-with-crewai-80b8cb55fa43?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/80b8cb55fa43</guid>
            <category><![CDATA[agents]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[agentic-ai]]></category>
            <category><![CDATA[multiagent-system]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Mon, 27 Jan 2025 17:54:37 GMT</pubDate>
            <atom:updated>2025-04-01T08:09:00.664Z</atom:updated>
            <content:encoded><![CDATA[<h4>LLM Agents are non-deterministic by nature: implement proper guardrails for your AI Application</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*fHk5jwzM4hK1pg0c" /><figcaption>Photo by <a href="https://unsplash.com/@firi?utm_source=medium&amp;utm_medium=referral">Muhammad Firdaus Abdullah</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Given the non-deterministic nature of LLMs, it’s easy to end up with outputs that don’t fully comply with what our application is intended for. A well-known example is Tay, the Microsoft chatbot that famously started posting offensive tweets.</p><p>Whenever I’m working on an LLM application and want to decide if I need to implement additional safety strategies, I like to focus on the following points:</p><ul><li><strong>Content Safety</strong>: Mitigate risks of generating harmful, biased, or inappropriate content.</li><li><strong>User Trust</strong>: Establish confidence through transparent and responsible functionality.</li><li><strong>Regulatory Compliance</strong>: Align with legal frameworks and data protection standards.</li><li><strong>Interaction Quality</strong>: Optimize user experience by ensuring clarity, relevance, and accuracy.</li><li><strong>Brand Protection</strong>: Safeguard the organization’s reputation by minimizing risks.</li><li><strong>Misuse Prevention</strong>: Anticipate and block potential malicious or unintended use cases.</li></ul><p>If you’re planning to work with LLM Agents soon, <strong>this article is for you</strong>.</p><h3>What are guardrails?</h3><p>In this context, implementing guardrails for an Agent means ensuring that the first output from the Agent is not the final answer.</p><p>Technically speaking, you want to evaluate the Agent’s output based on specific constraints and, if necessary, force the Agent to regenerate its answer until it meets your requirements.</p><p>For example, imagine an application that summarizes all the emails you’ve received over the past month. You’ve specified that personal information, such as the sender’s name, must be anonymized. However, LLMs can sometimes “forget” this condition due to their unpredictable nature. In such cases, you can rely on an additional step to verify whether your strict condition has been met, since it’s a critical requirement.</p><h3>Intro to CrewAI</h3><p><a href="https://docs.crewai.com/introduction">CrewAI</a> is my go-to framework whenever I work with Agents. It’s simple, backed by a strong community, open source, and completely focused on Agents. It also comes with plenty of extra functionalities, making it a very appealing choice.</p><p>Before diving into how to implement guardrails with CrewAI, let me briefly introduce the main components we’ll be working with.</p><h4>Agents, Tasks, and Crews</h4><p>In CrewAI, there’s a clear separation between the <a href="https://docs.crewai.com/concepts/tasks"><strong>Tasks</strong></a> and the <a href="https://docs.crewai.com/concepts/agents"><strong>Agent</strong></a> itself. This separation allows you to decouple what would otherwise be part of a single, large prompt. By keeping these two concepts distinct, you can clearly define the role of the Agent and what the Agent is supposed to do.</p><pre># Fitness Tracker Agent<br>fitness_tracker_agent = Agent(<br>    llm=llm,<br>    role=&quot;Fitness Tracker&quot;,<br>    backstory=&quot;An AI that sets goals, tracks progress, and recommends workouts.&quot;,<br>    goal=&quot;Set goals, track progress, and recommend workouts.&quot;,<br>    verbose=True,<br>)<br><br># Fitness Tracker Task<br>set_and_track_goals = Task(<br>    description=f&quot;Set the fitness goal ({fitness_goal}), track progress, and use weight history: {historical_weight_data}.&quot;,<br>    expected_output=&quot;A muscle gain plan with tracking.&quot;,<br>    agent=fitness_tracker_agent,<br>)</pre><p>In this example, we have a fitness Agent responsible for creating a muscle gain plan based on the fitness goal and historical weight data. As you can see, the fitness_tracker_agent doesn’t inherently know <strong>what</strong> to do until we create a Task and specify which agent will handle it.</p><p>Finally, we bring all the Tasks and Agents together into a <a href="https://docs.crewai.com/concepts/crews"><strong>Crew</strong></a>, which forms the heart of our application.</p><pre># Crew setup<br>crew = Crew(<br>    agents=[fitness_tracker_agent, recommendation_agent],<br>    tasks=[set_and_track_goals, fetch_fitness_recommendations, provide_workout_plan],<br>    planning=True,<br>)</pre><p>The final step is to execute our Crew using the input parameters that will be passed to the Tasks — in this case, the fitness goal and the historical weight data.</p><h4>Flows</h4><p>What we’ve just covered is enough to build a simple Crew, but it’s not sufficient to create a fully functional agentic application with guardrails. The next concept we need to master is <a href="https://docs.crewai.com/concepts/flows"><strong>CrewAI Flows</strong></a>.</p><p>The idea behind Flows is to easily create dynamic AI workflows with chained Tasks, seamless state management, event-driven responsiveness, and flexible control flow for conditions, loops, and branching.</p><p>The following decorators help manipulate the flow of execution:</p><ul><li><strong>@start()</strong>: Marks the entry point of the Flow and initiates Tasks when the Flow begins.</li><li><strong>@listen()</strong>: Executes a method when a specific Task or event is completed.</li><li><strong>@router()</strong>: Directs the Flow to different paths based on conditions or outcomes.</li></ul><pre>from crewai.flow.flow import Flow, listen, start<br>from pydantic import BaseModel<br><br>class ExampleState(BaseModel):<br>    counter: int = 0<br>    message: str = &quot;&quot;<br><br>class StateExampleFlow(Flow[ExampleState]):<br><br>    @start()<br>    def first_method(self):<br>        self.state.message = &quot;Hello from first_method&quot;<br>        self.state.counter += 1<br><br>    @listen(first_method)<br>    def second_method(self):<br>        self.state.message += &quot; - updated by second_method&quot;<br>        self.state.counter += 1<br>        return self.state.message<br><br>flow = StateExampleFlow()<br>final_output = flow.kickoff()<br>print(f&quot;Final Output: {final_output}&quot;)<br>print(&quot;Final State:&quot;)<br>print(flow.state)</pre><p>Additionally, Flows allow access to a shared object that stores and manages data (ExampleState), enabling seamless communication between Tasks and preserving context throughout the workflow.</p><h3>Guardrails with CrewAI Flow</h3><p>With the two simple concepts we’ve just covered, we’re ready to enhance our AI Agent. In this example, I’ll demonstrate how to create a multi-agent AI application capable of generating text and verifying whether the text contains violent content before providing the output.</p><p>The check for violence in the text occurs within the application itself. Thanks to Flow’s state management, we can control how often the text is regenerated, preventing infinite loops. This approach introduces a level of determinism to something that is inherently non-deterministic.</p><h4>Imports</h4><p>The primary library used is <strong>CrewAI</strong>, but we’ll also import <a href="https://docs.pydantic.dev/latest/"><strong>Pydantic</strong></a> to create a BaseModelclass, as CrewAI’s documentation requires.</p><blockquote>For this example, we’ll assume two Agents and their corresponding Tasks have already been created as described earlier: one for generating text and another for checking it for violent content.</blockquote><pre>from typing import List<br>from pydantic import BaseModel, Field<br>from crewai import Flow, start, listen, router</pre><p>In addition to the Flow class, we’ll need to use the three decorators to build our application.</p><h4>State</h4><p>The <a href="https://docs.crewai.com/concepts/flows#flow-state-management"><strong>state</strong></a> is what we use to persist data throughout the Flow execution. The first piece of information we need to persist is the generated text. This is where we store the text across all iterations, updating it as necessary.</p><pre>class ViolenceCheckState(BaseModel):<br>    generated_text: str = &quot;&quot;<br>    contains_violence: bool = False<br>    generation_attempts_left: int = 2</pre><p>To control the Flow, we’ll also use a flag to indicate whether the text contains violence, as well as a counter to track how many generation attempts remain. These attributes will be accessed and updated during the Flow’s execution.</p><h4>Flow Class</h4><p>The class we’re implementing consists of methods designed to control the flow of the application. Let’s build it step by step, starting with the __init__ function.</p><pre>class ViolenceCheckFlow(Flow[ViolenceCheckState]):<br>    topic: str = Field(description=&quot;Topic for text generation&quot;)<br><br>    def __init__(self, topic: str):<br>        super().__init__()<br>        self.topic = topic<br>    ...</pre><p>So far, it’s business as usual. We’re simply initializing the sole attribute of our class. What’s new here is the ViolenceCheckState Pydantic model, which we pass to the superclass Flow. This model will represent our state.</p><pre>    ...<br>    @start()<br>    def generate_text(self):<br>        print(f&quot;Generating text based on input topic: {self.topic}&quot;)<br>        task = create_text_generation_task(self.topic)  # Pass the input topic to the task<br>        crew = Crew(agents=[text_generator_agent], tasks=[task])<br>        result = crew.kickoff()<br>        self.state.generated_text = result.raw<br>        print(&quot;Text generated!&quot;)<br><br>    @listen(generate_text)<br>    def validate_text_for_violence(self):<br>        print(&quot;Validating text for violence...&quot;)<br>        task = create_violence_check_task(self.state.generated_text)<br>        crew = Crew(agents=[violence_checker_agent], tasks=[task])<br>        result = crew.kickoff()<br>        self.state.contains_violence = &quot;Violence&quot; in result.raw<br>        print(&quot;Validation complete:&quot;, &quot;Violence detected&quot; if self.state.contains_violence else &quot;No violence detected&quot;)<br>    ...</pre><p>The first method must use the @start decorator to define the starting point of our Flow. It’s followed by a second method, which listens to the first one and is executed after it.</p><p>These two methods perform the following Tasks:</p><ul><li><strong>generate_text</strong>: This method creates a Crew that generates text based on a given topic. The generated result is saved into the state via self.state.generated_text.</li><li><strong>validate_text_for_violence</strong>: This method uses a different Crew to check if the text contains violent content. If violence is detected, we set self.state.contains_violence to True.</li></ul><h4>Adding Complexity with Routing</h4><p>Here’s where it gets interesting. Now we use the @router decorator to direct the Flow based on whether the application needs to regenerate the text. This decision is based on the value of self.state.contains_violence.</p><pre>    ...<br>    @router(validate_text_for_violence)<br>    def route_text_validation(self):<br>        if not self.state.contains_violence:<br>            return &quot;safe&quot;<br>        elif self.state.generation_attempts_left == 0:<br>            return &quot;not_feasible&quot;<br>        else:<br>            return &quot;regenerate&quot;<br>    ...</pre><p>The route_text_validation method is executed immediately after validate_text_for_violence, as specified by the decorator. It checks the contains_violence attribute in the state and:</p><ul><li>Returns &quot;safe&quot; if no violence is detected.</li><li>Triggers a regeneration of the text if violence is detected and attempts remain.</li></ul><h4>Handling Signals</h4><p>The last part of our class includes three methods that listen for specific signals sent from route_text_validation: &quot;safe&quot;, &quot;regenerate&quot;, and &quot;not_feasible&quot;.</p><pre>    ...<br>    @listen(&quot;safe&quot;)<br>    def save_safe_text(self):<br>        with open(&quot;safe_text.txt&quot;, &quot;w&quot;) as file:<br>            file.write(self.state.generated_text)<br>        print(&quot;Safe text saved to file&quot;)<br><br>    @listen(&quot;regenerate&quot;)<br>    def regenerate_text(self):<br>        self.state.generation_attempts_left -= 1<br>        self.generate_text()<br><br>    @listen(&quot;not_feasible&quot;)<br>    def notify_user(self):<br>        print(&quot;Generated text contains violence and further attempts are not feasible.&quot;)<br>    ...</pre><p>Here’s how each scenario is handled:</p><ul><li><strong>&quot;safe&quot;</strong>: If no violence is detected, the generated text is saved to a file.</li><li><strong>&quot;regenerate&quot;</strong>: If text regeneration is triggered, the generation_attempts_left counter is decremented, and the generate_text method is called again, restarting the process.</li><li><strong>&quot;not_feasible&quot;</strong>: This occurs when the maximum number of regeneration attempts (in this case, 2) is reached, and the application cannot produce a text free of violence.</li></ul><h3>Conclusions</h3><p>This approach has been a lifesaver for me. The implementation focuses on organizing the loop and handling iterations rather than reinventing the logic behind the application’s flow. In this example, I focused on checking whether the text contained violence and determining the appropriate actions if it did. I didn’t have to waste time managing the flow logic itself, thanks to this clean, built-in feature provided by the framework.</p><h4>More Use Cases</h4><p>Among the many use cases for this approach, I’d like to highlight query injection. This is more common than you might think, especially with the growing prominence of roles like “prompt engineering.” With CrewAI, you can create a Flow that evaluates initial queries to determine if an attacker is attempting to exploit a chatbot, for example.</p><h4>Challenges</h4><p>This is the framework way: it gives you a lot, but when something goes wrong, it can take everything back with interest. I’ve started simple applications only to find myself opening pull requests on GitHub to fix bugs after hours of work.</p><p>That said, it’s not as bad as it sounds. CrewAI is still my first choice for multi-agent applications. However, as with any new library, relying on it means accepting the risks and being prepared to address them.</p><p>If you want to know more about this library, <a href="https://www.youtube.com/watch?si=s4VrKDPQNayA_b_e&amp;v=I98l3wLJ5Oo&amp;feature=youtu.be">check out my last talk</a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IXwoVR6nrl5JLcefJTKi9g.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=80b8cb55fa43" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/how-to-implement-guardrails-for-your-ai-agents-with-crewai-80b8cb55fa43">How to Implement Guardrails for Your AI Agents with CrewAI</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Do you need an ergonomic keyboard?]]></title>
            <link>https://medium.com/design-bootcamp/do-you-need-an-ergonomic-keyboard-70c5fe1a4ffe?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/70c5fe1a4ffe</guid>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[typing]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[ergonomics]]></category>
            <category><![CDATA[keyboard]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Wed, 04 Sep 2024 13:35:06 GMT</pubDate>
            <atom:updated>2024-09-04T13:35:06.320Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Image of a typewriter" src="https://cdn-images-1.medium.com/max/1024/0*gm6sLoN290ZceBlH" /><figcaption>Photo by <a href="https://unsplash.com/@ohleighann?utm_source=medium&amp;utm_medium=referral">Leighann Blackwood</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Since I was a student, I have been looking for various ways to improve my typing posture, sitting position, and screen viewing habits. I implemented several solutions back then, mostly based on what I felt was right at the moment, hoping they were effective. However, I didn’t really know what I was doing. My knowledge was limited, as was my budget for trying out new stuff.</p><p>For example, I spent a lot of time searching for something that could properly support my back, thinking it would be a game changer. Unfortunately, I now realize that I was destined to fail because how can you sit correctly if you cannot adjust your desk height? Are my feet going to float? Is that fine? If I don’t feel any discomfort now, but what will happen after typing in this position for three months?</p><p>I had too many questions, and while you can trust the answers given by ergonomic experts for some of them, most of the time, it’s a subjective matter that requires time to determine if something is really going to work for you.</p><p>Another issue was that trying out new tools and equipment was expensive. A Herman Miller Aeron chair, for example, costs around €1.000, and you don’t even know if it’s the right chair for you. You can go to a showroom, but it’s impossible to tell if you like it without spending a couple of months using it.</p><p>Without diving into all the (very interesting) aspects of building an ergonomic workspace, let’s focus on one element that I, as a developer, care a lot about: <strong>keyboards</strong>.</p><h3>Background</h3><p>I’ve never been a keyboard expert, and I found out what a mechanical keyboard is quite late, I guess. I remember this guy typing on a very loud keyboard and enjoying it a lot. I never understood why, for me the ThinkPad keyboard was the best in the world.</p><p>At the same time, I wanted to level up my setup, mainly because I wanted to work on my posture. I always told myself:</p><blockquote>Just as someone who drives many kilometers a day needs a well-equipped car, I require a comfortable setup, given that I sit for 8 or more hours each day.</blockquote><p>At that point, in 2016, I started looking for what the tech world had to offer.</p><h4>Towards Split Keyboards</h4><p>I don’t remember if I specifically googled “split keyboard,” perhaps it was more like “ergonomic keyboard, neck pain, struggling developers.” The fact is, my attention was caught by the famous Ergodox Project, which is implemented and sold by Ergodox EZ.</p><p>The concept blew me away, but as a student, the price tag was definitely out of my reach.</p><figure><img alt="Image of the first ergodox design" src="https://cdn-images-1.medium.com/max/1000/0*l7vRqYcyT_Pbp5kb.png" /><figcaption>Image from <a href="https://www.ergodox.io/">https://www.ergodox.io/</a></figcaption></figure><p>Considering that none of my friends or university mates have heard of something like this, it might have been a topic discussed on a subreddit. That’s probably the only place I could have shared my thoughts.</p><p>The only company I’ve seen selling a keyboard based on the Ergodox design is <a href="https://ergodox-ez.com/">https://ergodox-ez.com/</a>. They’re now recognized as one of the major players in the market. They’ve not only promoted these keyboards but also helped shape the market with their excellent products.</p><h4>Rethinking my typing setup</h4><p>My favorite way of typing (and coding) was resting my hand on the ThinkPad and use my thumbs to quickly move between the space bar, the mouse buttons, and the trackpad. Given that the ThinkPad was the first one proposing this mouse buttons configuration, it was difficult for me to move to another keyboard.</p><figure><img alt="Image how I use the keyboard-trackpad combination on they ThinkPad" src="https://cdn-images-1.medium.com/max/640/1*qBaZ0nLX9dvp1CXjhpgrpw.gif" /><figcaption>Image from the Author</figcaption></figure><p>Unfortunately, I don’t consider this an ergonomic position. In fact, it was the opposite of what I was looking for, even though I was able to type quickly. My hands weren’t in a natural position, which forced my entire body, including my shoulders, to adapt to them being so close together.</p><p>This is why I never felt the need for a mechanical keyboard. While it might offer a more satisfying typing experience, it wouldn’t have made any ergonomic difference for me, and I would have even lost the “thumb mouse” feature.</p><p>After using Linux for years, I had to switch to a MacBook and once again changed my setup to a more traditional one: Apple Magic Keyboard and Magic Trackpad. I did enjoy having all the MacBook gestures available on the external trackpad, but the keyboard eventually started to feel uncomfortable.</p><h3>Exploring new solutions</h3><p>Here we are — I’m no longer a student, and I can finally afford an expensive keyboard! Well, almost.</p><p>Aside from the money, everything I mentioned before still holds true. However, in 2023, I have more options. Mechanical keyboards are everywhere, and there are many new exotic layouts available. The demand is higher, and plenty of people are building their own keyboards. <a href="https://www.youtube.com/watch?v=JqpBKuEVinw">Check out this great video from Ben Vallack.</a></p><p>After much research and hundreds of Reddit posts, I reduced my choices to three models:</p><ul><li><a href="https://www.zsa.io/voyager">ErgoDox EZ Voyager</a></li><li><a href="https://dygma.com/pages/defy">Dygma Defy</a></li><li><a href="https://www.moergo.com/collections/glove80-keyboards">MoErgo Glove80</a></li></ul><p>My goal was to test each one thoroughly to see which worked best for me (or, if none did, return to my Magic Keyboard). The reason I focused solely on split keyboards is that I believe they’re the only way to type in a natural position, without bending the wrists or hunching the shoulders, as explained <a href="https://www.youtube.com/watch?v=1C2bJkzIaPE">here</a> and showed in the picture.</p><figure><img alt="Image of the angle of the wrist when typing on a classical keyboard" src="https://cdn-images-1.medium.com/max/960/1*2f3_yxF2b9dvPp8L4vZHiA.jpeg" /><figcaption>Image from the Author</figcaption></figure><p>Despite the positive reviews of the Voyager, a few minor details didn’t convince me, such as the completely flat setup with no tilting option. Given the price, I didn’t want to take the risk. So, I decided to focus all my attention on the Dygma and the Glove80.</p><p>Please note, this isn’t meant to be a comparison where one product outshines the other. This is simply my story, and if you happen to have similar needs, the keyboard I ended up choosing might be the right fit for you as well. It’s important to remember that we’re talking about two GREAT products, crafted by brilliant minds.</p><h3>Dygma Defy: The Spanish Beauty</h3><p>When I tried this I was blowned away. The quality of the caps is so high that for the first time I understood the hype around mechanical keyboard. These are custom keycaps made by the company specifically for the Defy, and I love them.</p><figure><img alt="The Dygma Defy Keyboard" src="https://cdn-images-1.medium.com/max/1024/1*FS3wqclhNgaRRE_tnXko6A.jpeg" /><figcaption>Image from the Author</figcaption></figure><p>The overall feeling is amazing, starting from the backlight till the case. I enjoyed typing on it, I really did.</p><p>This keyboard leverage the concept of the thumb being the strongest finger, while positioning the keys in orthogonally and following the length of the fingers.</p><h4><strong>What I loved about the Defy</strong></h4><p>Apart from the build quality, including the keycaps, I really appreciate the range of configuration options available, allowing you to tailor the keyboard to your exact needs. But what truly stood out to me is the software. It’s incredibly user-friendly, making it easy to configure the keyboard, and it offers a wealth of genuinely useful features.</p><p>Additionally, the backlighting helps you quickly recognize the layers you’re using. As a developer, for example, I have all my parentheses on a dedicated layer, so I don’t have to rely on awkward key combinations. <a href="https://www.youtube.com/watch?v=MZI4lz_toFY">Here’s an example.</a></p><h4>What didn’t work for me?</h4><p>First off, <em>it’s not an ergonomic keyboard</em>, at least not for me. When my hands rest on the keyboard, I still have to slightly raise my fingers, much like I would with any other “flat” keyboard. This makes my hands tired and makes me question if there’s really a universal definition of ergonomic.</p><p>While I find the always-on backlit keycaps very helpful, the battery life takes a significant hit because of it. Although the new firmware has optimized battery usage, I ultimately decided to turn the backlighting off.</p><p>Connection issues are a big deal for me. When I’m spending over €400 on a keyboard, I expect it to connect seamlessly, whether I’m using a dongle or Bluetooth. Unfortunately, this hasn’t always been the case. I’m not sure if this problem has been resolved by the time you’re reading this, but I can say that the connection was not as stable as it is with the Glove80, as you’ll see in the following sections.</p><h3>Glove80: First of Its Kind</h3><p>Let’s not waste too much time here: <strong>this is my choice</strong>.</p><figure><img alt="The Glove80 keyboard" src="https://cdn-images-1.medium.com/max/1024/1*0e41OUVp3m0CNOA9Z5LUEQ.jpeg" /><figcaption>Image from the Author</figcaption></figure><p>At first glance, it was overwhelming. If you’re not already into split or ortho-linear keyboards, it’s hard even to consider a product like this — there are just too many new concepts to take in! In this case, the most important functions are assigned to the thumbs, but what probably stands out the most is the <strong>curved design</strong>.</p><p>I remember placing my hands on it right after unboxing, feeling nervous that I might not like it or that I’d be incredibly slow typing on it. Instead, the opposite happened — the curved design actually made it easy to reach all the keys, <strong>even up to the number row</strong>. Plus, you have a full keyboard, which is quite rare lately.</p><h4>Glove80 vs Defy</h4><p>Comparing it to a great product like the Defy is the best way to illustrate why I love my Glove80. I won’t go into all the features — there are plenty of in-depth reviews on YouTube — but I want to highlight what ultimately helped me decide: the curved design.</p><blockquote>This design choice might not work for everyone, but it’s perfect for me.</blockquote><p>When my hands rest on the keyboard, I don’t feel any tension, and the keys are all easily reachable without being too close together, making the typing experience truly unique. The outer rows are slightly elevated, making it easier for the pinkies to reach the keys — a genius idea. While the thumb keys may not be as “cool” as those on the Defy, I find them much more comfortable because my thumbs naturally reach and rest on them without any effort.</p><figure><img alt="Image of how much close to the desk the two keyboards are" src="https://cdn-images-1.medium.com/max/1024/1*Zs3xu7Cq3Ieu89_TGl8SFw.jpeg" /><figcaption>Image from the Author</figcaption></figure><p>Check how close you can stay to the desk, while having some tenting. Something impossible with the Defy.</p><p>Another significant advantage of the Glove80 is its seamless connection to my laptop. It always works flawlessly, without the need for any extra dongles or adapters. This is especially important for me, as my primary focus is on typing, not gaming, where a low-latency connection might be more critical.</p><p>Is there something I don’t like about the Glove80? Honestly, no. I’ve seen a few people complain about the quality of the keycaps, but I don’t really share their concerns — <a href="https://www.moergo.com/collections/moergo-keycap-collection">it’s never bothered me</a>. As for the fact that the Glove80 is made of plastic, I understand why. Given its unique shape, using aluminum would have been prohibitively expensive or even impossible, so I don’t see this as an issue but an exceptionally curated engineering decision. However, I’ll provide more updates on the build quality in a few years :)</p><h3>Conclusions</h3><figure><img alt="Comperison of Defy vs. Glove80" src="https://cdn-images-1.medium.com/max/1024/1*qHPHIyUVaWPqt6dIOaTv-A.jpeg" /><figcaption>Image from the Author</figcaption></figure><p>I was skeptical and thought finding a keyboard that genuinely made me happy was impossible. But I was wrong — I found the one. <br>I decided to return the Defy (thanks to the excellent support from the company), but I sometimes wish to keep both and switch between them.</p><p>If you have the budget and want to elevate your typing experience, you probably can’t go wrong with either of them. However, if ergonomics is your top priority, <strong>I believe the Glove80 really nails it.</strong></p><p>Finally, many asked me how fast I type with my new setup. Here is my score from <a href="https://monkeytype.com/">Monkeytype</a>:</p><figure><img alt="Screenshot of my personal typing record" src="https://cdn-images-1.medium.com/max/1024/1*upoyO8hQkxAer4gQg66UBQ.jpeg" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=70c5fe1a4ffe" width="1" height="1" alt=""><hr><p><a href="https://medium.com/design-bootcamp/do-you-need-an-ergonomic-keyboard-70c5fe1a4ffe">Do you need an ergonomic keyboard?</a> was originally published in <a href="https://medium.com/design-bootcamp">Bootcamp</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Data Science Mentor]]></title>
            <link>https://pub.towardsai.net/the-data-science-mentor-eee4b54632b4?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/eee4b54632b4</guid>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[mentoring]]></category>
            <category><![CDATA[careers]]></category>
            <category><![CDATA[advice]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Fri, 23 Aug 2024 19:01:37 GMT</pubDate>
            <atom:updated>2024-08-23T19:01:37.038Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*mfsWiNvrN8DqJb40" /><figcaption>Photo by <a href="https://unsplash.com/@syinq?utm_source=medium&amp;utm_medium=referral">Susan Q Yin</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>We all had a mentor. Sometimes, it is a parent or just someone who dropped in your life at the right time and gave you the tools to achieve something great you always wanted to achieve. I clearly remember the individuals who shaped me, and helped me to see the paths in front of me more clearly. Then, when I started working as a Data Scientist, I remember being lost at first, overwhelmed with these great problems my company wanted me to solve. I did my best, but the turning point for me was collaborating with seniors (not always from data science) who knew exactly what I was going through, helped me shape my career, and contributed to what I am today. I quickly realized that many lessons couldn’t be learned from books alone. I needed guidance from people and professionals to show me the way. Despite having many tools and technical knowledge, I often felt a lingering sense of being lost.</p><p>Over the past year and a half, I have worked as a Data Science mentor. This role is quite broad, as my experience has shown that collaboration with a mentee can take many forms, ranging from purely technical sessions to high-level career path development.</p><p>It has been a fantastic experience where I let my brain explode under the questions of my mentee, releasing knowledge I wasn’t sure would ever be useful to someone. Apparently, I was wrong, as many people seek advice, and while helping them, I learned about many new problems and challenges faced by aspiring data scientists and companies.</p><h4>Is this article for you?</h4><p>If you fall into any of these categories, this is definitely the article for you:</p><ul><li>You’re a mentee seeking advice</li><li>You’re an aspiring mentor eager to help others</li><li>You’re part of an organization looking to support your employees</li><li>Or you just enjoy my stories!</li></ul><h3>The Dawn of the Mentor</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*i9tYqBC6plDBVrZD" /><figcaption>Photo by <a href="https://unsplash.com/@_alikokab_?utm_source=medium&amp;utm_medium=referral">Ali Kokab</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>The non-deterministic nature of many problems a Data Scientist has to solve can make small challenges appear significant, which can be frustrating for companies and aspiring data scientists. It requires experience to say confidently:</p><blockquote>I’m confident that we should proceed in this way</blockquote><p>Regardless of how accurate your model is. Under the right circumstances, a mentor can make this process less painful and smoother.</p><p>I see two key players in the search for a mentor. The first is the <strong>potential mentee</strong>, who may be aware of their needs and ready to take action. The second is often an <strong>organization</strong> that may struggle to fully support its employees due to a possible lack of expertise within its teams.</p><p>Let’s analyze these two figures to understand them better and generalize their needs, ultimately creating useful guidelines.</p><h4>Data Mentees</h4><p>Even though it’s been a while since the famous article “<a href="https://hbr.org/2012/10/data-scientist-the-sexiest-job-of-the-21st-century">Data Scientist: The Sexiest Job of the 21st Century</a>” was published, I still consider it a relatively new field, primarily due to our challenges. On one hand, best practices are still evolving and are not as well-established as those in software engineering. On the other hand, domain knowledge, which demands real-world experience, plays a crucial role. Combining these two aspects is no easy task.</p><p>I’ve enjoyed working with many individuals in this field and noticed three broad categories of people.</p><p>The first group consists of <strong>aspiring data scientists</strong> coming from completely different backgrounds. They often feel overwhelmed by the vast amount of online courses and TikTok videos claiming to teach how to (not) become a data scientist in just five steps.</p><p>The second group consists of engineers, typically from the tech industry, who are<strong> transitioning into data science</strong>. Their motivation is often rooted in hands-on experience with relevant technologies rather than simply following a trend.</p><p>Lastly, <strong>junior or intermediate data scientists</strong> actively seek guidance. This is often due to a lack of senior team members, leading to a need for direction and advice when making critical decisions.</p><h4>Organizations</h4><p>Many of my collaborations have been directly sponsored by companies because <strong>they recognize their employees&#39; need for support</strong> in areas that the organization cannot fully provide. This is a very honest and proactive approach to fostering continuous learning, rather than simply paying for a Udemy subscription that often goes unused.</p><p>This scenario typically involves junior data scientists who lack the support of a senior figure but are still expected to tackle complex tasks. Bringing in a “part-time senior data scientist” can make a significant difference in these cases. The ultimate goal is mentoring and developing internal professionals to the point where they feel confident proceeding independently.</p><p>My suggestion is to actively listen to employees and provide a learning service that benefits both the organization and the individual. This approach creates a win-win situation, fostering growth and development on both sides. This kind of engagement leads to one of the most effective and rewarding learning experiences possible.</p><h3>What is the Mentoring about?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JV5D4nz4olwninGj" /><figcaption>Photo by <a href="https://unsplash.com/@yuliamatvienko?utm_source=medium&amp;utm_medium=referral">Yulia Matvienko</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>I cannot count how many times I’ve been asked this question. To me, it is one of the hardest. Each request is a custom request, and each path needs to be tailored around the mentee. There are many common factors, of course, and I learned how to optimize this process, but this is exactly the reason why I cannot just make a YouTube video that works for everyone.</p><h4>Defining a Plan</h4><p>The first step is having a clear plan so the mentor can provide guidance and ensure the process will eventually conclude. Some people prefer a structured approach with a list of tasks and assignments, while others like to keep sessions more dynamic, adapting the collaboration based on their weekly challenges. For example, here’s a list of things I always make sure are in place before someone steps into the interview process:</p><ul><li>A well-crafted <strong>LinkedIn</strong> profile includes useful links to past projects and comprehensive details about their experience, including roles and key projects.</li><li>A <strong>GitHub</strong> account featuring personal projects demonstrating their interest and eagerness to explore new ideas.</li><li>Ensure the mentee is comfortable with the <strong>interview stages</strong>—both technical and non-technical—so they know what to expect. This may include conducting some mock interviews.</li><li>Practicing <strong>live coding</strong> with clear, well-explained comments.</li></ul><h4>Be Realistic</h4><p>In either case, whether I formalize a plan or not, I always start by asking what the <strong>goals</strong> are. This step is crucial because many people don’t know what to expect from mentoring, and it’s important to be both realistic and proactive. For example, when helping someone who wants to land a job as a Data Scientist, it’s key to clarify that while no one can guarantee a job within a set timeframe, we can focus on being well-prepared and controlling all the factors within our reach. That’s far more realistic than claiming, “I can guarantee you’ll get hired if you choose me as a mentor.”</p><h4>Stop the Mentoring!</h4><p>Whether you’re a mentor or a mentee, it’s important not to <strong>get lost in the mentoring</strong> process. I’ve worked with very smart individuals who extended the mentoring without a clear reason, and while this was financially beneficial for me, I realized my job was already done. We took a break and resumed after they had applied what they had learned.<br>On the other hand, a mentor isn’t a (real) superhero and can’t help everyone. Some areas are simply beyond my expertise. When I recognize that I’m not the right person, I either recommend someone else or explain that I won’t be able to provide the best guidance in that area.</p><h3>Conclusions</h3><p>I see many new platforms connecting mentors and mentees, which shows that the demand is high and the need is real. I’ve also noticed that data science tends to be the most in-demand topic, highlighting the high demand for talent in this field and the relatively weak supply. I believe boosting your career with a mentor under the right circumstances can be very beneficial and help bridge this gap.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eee4b54632b4" width="1" height="1" alt=""><hr><p><a href="https://pub.towardsai.net/the-data-science-mentor-eee4b54632b4">The Data Science Mentor</a> was originally published in <a href="https://pub.towardsai.net">Towards AI</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Data Speaker’s Blueprint: Turning Analytics into Applause]]></title>
            <link>https://medium.com/data-science/the-data-speakers-blueprint-turning-analytics-into-applause-96fb12a0ef39?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/96fb12a0ef39</guid>
            <category><![CDATA[public-speaking]]></category>
            <category><![CDATA[storytelling]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[data-analysis]]></category>
            <category><![CDATA[data]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Sun, 21 Jan 2024 15:56:37 GMT</pubDate>
            <atom:updated>2024-01-24T12:12:52.214Z</atom:updated>
            <content:encoded><![CDATA[<h4>My experiences and learnings as a public speaker in Data Science.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q0QRa2Nh4DeoT7c52E57cg.jpeg" /><figcaption>Me at the Applydata Summit 2023 in Berlin</figcaption></figure><p>During my career as a Data Scientist, I’ve attended many conferences and meetups. When I started my job, many were struggling to understand what Data Science was and how to leverage the growing cloud computing solutions. <strong>It always felt like a jungle!</strong></p><p>That’s why connecting with the data community through meetups and other local events became essential for me. At some point, someone invited me to present a project I was working on. It was then I realized how much I enjoy sharing and explaining my work!</p><p>Since then, I’ve had the pleasure of speaking at various conferences, including <a href="https://odsc.com/california/">ODSC</a>, <a href="https://python.ie/pycon-2023/">PyCon</a>, and <a href="https://datainnovationsummit.com/">Data Innovation Summit</a>, among others. Each time I’m asked:</p><blockquote>“How do you find the right story for a conference?”</blockquote><blockquote>“Aren’t you scared of making mistakes while presenting something technical?”</blockquote><p>These questions, among others I’ve received, made me realize it’s time to share what I’ve learned over the years and, hopefully, inspire new data experts to share their knowledge.</p><h3>Why do we need Data Speakers?</h3><p><em>Data</em> is tough! Companies often don’t really know what they’re looking for, pushing data enthusiasts to find solutions for problems that sometimes just can’t be solved. <strong>Now, imagine how helpful it would be to connect with someone facing the same challenges, who might offer the very answer you’ve been seeking</strong>. Or perhaps simply someone you can relate to, where you can share and delve deeply into the work you’re doing.</p><p>This is precisely why we need skilled communicators in our field. I still vividly recall when this amazing Data Engineer shared how he resolved a deployment issue with AWS Lambda during his presentation. This issue had been a challenge for me for several weeks.</p><p>On another note, listening to someone present a use case can be enlightening. It’s a way to discover certain solutions and understand how they can be applied. Moreover, if you’re truly passionate about your work, presenting your ideas and opening them up for discussion can be immensely enjoyable. It’s an opportunity to receive feedback from a diverse array of people.</p><p>I also hold the conviction that in a world where AI, such as applied Large Language Models (LLMs), has significantly advanced, there’s an increasing need for enhanced communication. This is crucial to explain the layers of complexity that exist between us and the technologies that have become part of our lives.</p><h4>I don’t have anything to say</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RG8hkhAqPSN0HGOnvELaMA.png" /><figcaption>Generated with Dall-E</figcaption></figure><p>Sadly, this is a sentiment I often encounter. To me, it always echoes like:</p><blockquote>“I don’t have the right to speak because I don’t have anything to say.”</blockquote><p>But this couldn’t be further from the truth. There’s always something to say, especially when you’re immersed in the world of data every day. You’re surrounded by stories and challenges that defy simple, deterministic solutions. To me, that’s the perfect starting point for something extraordinary!</p><p>We sometimes overlook the significance of our work, merely because it’s part of our daily conversations. We discuss it with our boss, colleagues, and forget that outside our bubble, many companies and individuals are still navigating the basics of data and AI. For example, I know many who aren’t familiar with ChatGPT, despite its growing popularity. Take your insights beyond your immediate circle, and you’ll realize how vast your audience truly is!</p><p>Lastly, if you work in data, you are inherently a storyteller. It’s impossible to work in this field without transforming complex contexts into more digestible narratives. You might be doing it subconsciously, but you’re definitely doing it.</p><h3>Presentation as a Product: Tips and Tricks</h3><p>Consider crafting your presentation as you would any other product. Its value is crucial; without it, the presentation might not be worthwhile.</p><p>To elaborate, presenting to a conference is a collaborative effort involving the audience, the speaker, and the organizers. If your presentation doesn’t add value for these three key groups, it’s wise to step back and reassess its purpose.</p><p>I believe that a compelling talk begins with addressing a specific need. It could be something you’ve dedicated months to, leading to a realization that it’s worth sharing. Whether it’s about your successful solutions or your failures (and the lessons learned), it should stem from your personal expertise and diligent effort.</p><p>Before diving into some tips for crafting your presentation, let’s address what I believe is the elephant in the room:</p><blockquote>Aim to be a Data Advocate, not a Data Guru.</blockquote><p>I observe that the world is brimming with ‘gurus’ but has only a handful of true experts. When you think about taking the stage, view it as a platform for sharing knowledge rather than as a destination or a crowning achievement. The term “Guru” isn’t inherently negative, but in this context, I want to emphasize the distinction I’m making.</p><h4>Find the Topic</h4><p>When deciding on the topic for my next presentation, I begin with three basic yet essential questions:</p><ol><li><strong>What project am I currently immersed in?</strong></li><li><strong>What challenges have I recently faced in this work?</strong></li><li><strong>Will sharing this information be beneficial to others?</strong></li></ol><p>These questions are my starting point for pinpointing the ideal subject. The following step involves researching who else is discussing similar topics, through various channels like publications, talks, or Medium articles. This stage is vital as it requires a thorough understanding of current trends and developments, ensuring that my contribution stands out in some unique way.</p><p>Take, for instance, a <a href="https://towardsdatascience.com/how-i-made-my-girlfriend-happy-with-a-simple-telegram-bot-2be8e4b150e7">Medium article</a> I wrote a few years back. I wasn’t introducing something brand new; instead, the innovation lay in how I combined existing technologies to overcome a specific challenge. This experience then became the focus of a talk I gave to a local Python community in Hamburg.</p><h4>Craft your Slides Deck</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*R8Tcjb3DE942lr8-o1fcJQ.png" /><figcaption>Image from the Author</figcaption></figure><p>I firmly subscribe to the philosophy that “<strong>less text is better</strong>”, and I remain open to contrary views, though I’m quite steadfast in my belief! Instead of relying heavily on text, I suggest using visuals that succinctly explain your algorithm or employing brief bullet points as your guide. When presenting to an audience that may not be as deeply immersed in the subject as you are and has likely sat through other presentations, overloading them with text can be counterproductive. The result? A disengaged audience and the feeling that your message isn’t getting through. Just picture enduring a 30-minute presentation under such conditions!</p><p>Maintain a minimalistic approach with your presentation slides, showcasing only the crucial elements that complement your talk. Understand that it’s impossible to cover every detail. Instead, provide a few links to your work for those in the audience who wish to explore the topic further.</p><blockquote>Remember to acknowledge the work of others in your presentation. It’s important to give credit for original content, as this isn’t about competition. By recognizing the contributions of others, you significantly elevate the quality of your presentation, demonstrating a thorough understanding of the subject matter.</blockquote><h4>Explain like no one knows what you’re talking about</h4><p>This is your moment to truly stand out, after all the effort you’ve put into your subject! Aim to captivate everyone’s attention. Ensure the experts in the room are pleased to hear about familiar topics, while those less knowledgeable feel included and able to grasp your points. Be observant of your audience; gauge whether they are keeping up with you. If time allows, lighten the mood with a joke to ease both your nerves and theirs. Engage your audience directly by asking a few questions during your talk to maintain high levels of attention.</p><p>I view this as a strategic game where you must actively prevent the audience’s attention from waning. Incorporate as many additional details as possible to help the audience connect with you and the problem you tackled. This might include some background on your company or what methods were used before your solution came into play.</p><blockquote>That’s why we call it Story Telling and not Data Telling.</blockquote><p>Ultimately, the question arises: should you script your speech and commit it to memory? In my view, that’s a matter of personal preference. Personally, I tend not to. This is mainly because I prefer to let the flow of ideas guide my presentation, allowing me to spontaneously include thoughts I might not have initially considered. This approach, largely driven through experience, makes the whole process much more enjoyable, in my opinion.</p><h3>Final Thoughts</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_GeFtxQ-f15kVhwJiaF00w.png" /><figcaption>Generated with Dall-E</figcaption></figure><p>While for some, the scary aspect might be standing on stage, for me, the real battle was against imposter syndrome. This feeling seems to be a common thread among data scientists. Hence, stepping out to talk about a project that’s somewhat nebulous or didn’t quite work out as expected can be quite challenging. Thankfully, I overcame my apprehensions, and thanks to numerous incredible speakers I’ve encountered along my journey, I’ve been able to look back at my achievements and recognize that many are indeed worth sharing.</p><p>So, break out of your bubble and find the stage that suits you best. Whether it’s a topic in Data Science or a Data Engineering use case, gather all your insights, step out, and share them with the world.</p><p>If you are in need of support or want to connect, feel free to reach out: <a href="https://www.aromano.dev/">https://www.aromano.dev/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=96fb12a0ef39" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/the-data-speakers-blueprint-turning-analytics-into-applause-96fb12a0ef39">The Data Speaker’s Blueprint: Turning Analytics into Applause</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building Agile Data Dashboards: An Introduction to Streamlit]]></title>
            <link>https://alerom90.medium.com/building-agile-data-dashboards-an-introduction-to-streamlit-1aa49e984ee6?source=rss-c05915df6ba4------2</link>
            <guid isPermaLink="false">https://medium.com/p/1aa49e984ee6</guid>
            <category><![CDATA[data]]></category>
            <category><![CDATA[web-app-development]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[dashboard]]></category>
            <category><![CDATA[streamlit]]></category>
            <dc:creator><![CDATA[Alessandro Romano]]></dc:creator>
            <pubDate>Thu, 25 May 2023 15:07:26 GMT</pubDate>
            <atom:updated>2024-01-28T16:24:17.469Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*AIxXIYFQ1i0s4iR3" /><figcaption>Photo by <a href="https://unsplash.com/@dengxiangs?utm_source=medium&amp;utm_medium=referral">Choong Deng Xiang</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>The evolution of technology and the exponential increase in data generation have made data analysis and visualization an indispensable part of our world. From data scientists to business analysts, marketers, and decision-makers, the ability to transform raw data into actionable insights is a critical skill. This is where data dashboards come into play.</p><p>Data dashboards are information management tools that visually track, analyze and display key performance indicators (KPIs), metrics and key data points. <strong>Streamlit</strong>, an open-source <strong>Python</strong> library, is one of the most powerful and user-friendly tools for building interactive data dashboards and web applications. It’s simple to use, flexible, and requires little to no web development experience.</p><h4>Getting Started with Streamlit</h4><p>Setting up a Streamlit dashboard is straightforward. Let’s start by installing Streamlit using pip:</p><pre>pip install streamlit</pre><p>Once installed, you can create a new Python file and import Streamlit:</p><pre>import streamlit as st</pre><p>With Streamlit, you can easily include various components and data visualizations. Let’s create a simple dashboard with a title, a text input, a button, and a simple chart:</p><pre>import streamlit as st<br>import pandas as pd<br>import numpy as np<br><br># Set up the title of the web app<br>st.title(&#39;My First Streamlit App&#39;)<br><br># Input box<br>user_input = st.text_input(&quot;Enter some text&quot;, &quot;&quot;)<br><br># Button<br>button_clicked = st.button(&#39;Click me!&#39;)<br><br># Simple chart<br>chart_data = pd.DataFrame(<br>    np.random.randn(20, 3),<br>    columns=[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;])<br>st.line_chart(chart_data)<br><br>if button_clicked:<br>    st.header(f&#39;You entered: {user_input}&#39;)</pre><p>When you run this script using streamlit run your_script.py in the command line, you&#39;ll get a web application with a title, a text box where users can enter some text, a button that displays the entered text when clicked, and a line chart.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1UPqHu0zCKhhWqdrOv1xMA.png" /></figure><h4>A More Advanced Example</h4><p>Now let’s consider a more complex example — we will create a simple machine learning model using the Iris dataset and then develop an interface using Streamlit to interact with this model.</p><pre>import streamlit as st<br>from sklearn import datasets<br>from sklearn.ensemble import RandomForestClassifier<br>import pandas as pd<br><br># Load Iris dataset<br>iris = datasets.load_iris()<br>X = iris.data<br>y = iris.target<br>iris_df = pd.DataFrame(X, columns=iris.feature_names)<br><br>st.write(&quot;&quot;&quot;<br># Simple Iris Flower Prediction App<br>This app predicts the **Iris flower** type!<br>&quot;&quot;&quot;)<br><br># Sidebar<br>st.sidebar.header(&#39;User Input Parameters&#39;)<br><br>def user_input_features():<br>    sepal_length = st.sidebar.slider(&#39;Sepal length&#39;, 4.3, 7.9, 5.4)<br>    sepal_width = st.sidebar.slider(&#39;Sepal width&#39;, 2.0, 4.4, 3.4)<br>    petal_length = st.sidebar.slider(&#39;Petal length&#39;, 1.0, 6.9, 1.3)<br>    petal_width = st.sidebar.slider(&#39;Petal width&#39;, 0.1, 2.5, 0.2)<br>    data = {&#39;sepal_length&#39;: sepal_length,<br>            &#39;sepal_width&#39;: sepal_width,<br>            &#39;petal_length&#39;: petal_length,<br>            &#39;petal_width&#39;: petal_width}<br>    features = pd.DataFrame(data, index=[0])<br>    return features<br><br>df = user_input_features()<br><br># Show user input in main screen<br>st.subheader(&#39;User Input parameters&#39;)<br>st.write(df)<br><br># Create and train the model<br>clf = RandomForestClassifier()<br>clf.fit(X, y)<br><br># Make prediction<br>prediction = clf.predict(df)<br>prediction_proba = clf.predict_proba(df)<br><br># Show prediction<br>st.subheader(&#39;Class labels and their corresponding index number&#39;)<br>st.write(iris.target_names)<br><br>st.subheader(&#39;Prediction&#39;)<br>st.write(iris.target_names[prediction])<br><br>st.subheader(&#39;Prediction Probability&#39;)<br>st.write(prediction_proba)</pre><p>This code will create a web application where users can input the measurements of an Iris flower using four sliders. The measurements are then fed into a RandomForestClassifier which predicts the type of Iris flower.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AlML0yCRrbHWgMYb0Siu5Q.png" /></figure><p>Here’s what’s happening in detail in the code above:</p><ol><li><strong>Streamlit API</strong>: Functions like st.write(), st.subheader(), st.sidebar.slider(), etc. are used to add text, headers, and interactive widgets to the app.</li><li><strong>User Input</strong>: The user_input_features() function collects inputs from sidebar sliders, representing Iris flower features.</li><li><strong>Data Handling</strong>: User inputs are assembled into a DataFrame, serving as the model input for prediction.</li><li><strong>Model Training</strong>: A RandomForestClassifier from Scikitearn is trained on the Iris dataset, illustrating a simple use of machine learning.</li><li><strong>Prediction</strong>: The trained model predicts the flower type based on user input, displaying results and probabilities on the main screen.</li><li><strong>Interface</strong>: The web app has a main screen for displaying results, and a sidebar with sliders for user input.</li></ol><blockquote>In a real-world application, you should split your data into training and testing sets and evaluate the performance of the model. This example keeps things simple for the purpose of illustrating the power of Streamlit :)</blockquote><h3>Diving Deeper into Streamlit’s Limitations</h3><p>While Streamlit’s simplicity and ease of use are clear benefits, it’s important to understand its limitations when building more complex applications. Let’s explore some of these limitations with code examples.</p><h4>Limited Customization</h4><p>One of the limitations of Streamlit is its limited customization. Let’s say you want to place two graphs side by side. In traditional web development, you could easily specify the position of your elements. With Streamlit, layout manipulation is more constrained. Here’s an example:</p><pre>import streamlit as st<br>import matplotlib.pyplot as plt<br><br># Create two plots<br>fig1, ax1 = plt.subplots()<br>ax1.plot([1, 2, 3, 4])<br><br>fig2, ax2 = plt.subplots()<br>ax2.plot([4, 3, 2, 1])<br><br># Display the plots<br>st.pyplot(fig1)<br>st.pyplot(fig2)</pre><p>In this code, even though we created two separate plots, they will be displayed one after the other, not side by side. However, Streamlit has introduced new layout options with columns:</p><pre>col1, col2 = st.columns(2)<br><br>with col1:<br>    st.pyplot(fig1)<br>with col2:<br>    st.pyplot(fig2)</pre><p>Although this helps, Streamlit’s ability to control the layout of your application is still less flexible compared to traditional web development tools.</p><h4>Stateless Design</h4><p>Streamlit’s stateless design can also be a limitation. This means that Streamlit reruns the entire script from top to bottom each time an input changes, which can be problematic with complex applications that require maintaining a state across interactions.</p><p>For instance, suppose we have a button that’s supposed to increment a counter each time it’s clicked:</p><pre>import streamlit as st<br><br># Set up counter<br>counter = 0<br><br>if st.button(&#39;Increment&#39;):<br>    counter += 1<br><br>st.write(f&#39;Counter: {counter}&#39;)</pre><p>In this code, clicking the ‘Increment’ button does not increase the counter as one might expect. This is because each time the button is clicked, the script reruns from the top, resetting the counter back to zero.</p><p>Streamlit has provided a workaround for this issue with the introduction of Session State, allowing you to maintain state across reruns:</p><pre>import streamlit as st<br><br># Get the state<br>state = st.session_state<br><br># Set up counter in state if not already done<br>if &#39;counter&#39; not in state:<br>    state[&#39;counter&#39;] = 0<br><br>if st.button(&#39;Increment&#39;):<br>    state[&#39;counter&#39;] += 1<br><br>st.write(f&#39;Counter: {state[&quot;counter&quot;]}&#39;)</pre><p>Even though this provides a solution, managing state in Streamlit is less intuitive than in other web development frameworks and can become complex in larger applications.</p><p>Understanding these limitations is crucial when deciding if Streamlit is the right tool for your project. However, it’s worth noting that Streamlit is actively developed and improved, and many of these issues may be mitigated in the future.</p><h3>Who Should Use Streamlit?</h3><p>Streamlit is a powerful tool for creating interactive data dashboards and web applications with minimum hassle. But who is this tool really for?</p><h4>Data Scientists</h4><p>For data scientists, Streamlit is a dream come true. Traditionally, data scientists would have to rely on web developers to build dashboards that showcase their models or insights. With Streamlit, they can do it themselves, using the Python skills they already possess. It allows them to easily prototype, build, and deploy machine learning models, as well as share their results in an engaging, interactive format.</p><h4>Data Analysts</h4><p>Streamlit also offers a lot of value for data analysts. Analysts can use it to create compelling visualizations and dashboards, enabling them to effectively communicate their findings. The interactivity that Streamlit offers can make these presentations more engaging and insightful.</p><h4>Educators and Researchers</h4><p>Educators and researchers can also greatly benefit from Streamlit. It can be used to create interactive educational materials or to visualize research findings in an accessible way. This makes it a great tool for anyone looking to share knowledge or information.</p><h4>Product Managers and Business Leaders</h4><p>Streamlit can be an effective tool for product managers and business leaders as well. They can use it to rapidly prototype app ideas without having to write extensive code or rely on a full-fledged development team. It’s also a great tool for creating internal dashboards to track key metrics and KPIs.</p><p>In summary, Streamlit is a versatile tool that can bring value to a wide range of professions. If your work involves dealing with data, prototyping web applications, or you need a quick and simple way to create interactive dashboards, Streamlit is definitely worth a look.</p><h3>What I (don’t) Like</h3><p>There are a couple of things that are driving me crazy indeed, but with great features come big limitations! It’s a small price to pay if you want to implement a web app in a few seconds.</p><h4>Cons</h4><p>While Streamlit is incredibly user-friendly and powerful, it does have a few drawbacks:</p><ul><li><strong>Limited Customization</strong>: Streamlit’s simplicity comes at the cost of customization. Unlike traditional web development frameworks, it doesn’t provide fine-grained control over the UI.</li><li><strong>State Management</strong>: Its design is stateless by default. This could be a challenge when building complex applications, though there are workarounds available.</li><li><strong>Large Data Handling</strong>: While Streamlit can handle larger datasets by using caching, it may still struggle with very large datasets.</li></ul><h4>Pros</h4><p>Despite these drawbacks, Streamlit offers several compelling benefits:</p><ul><li><strong>Ease of Use</strong>: Streamlit’s biggest advantage is its simplicity. You can build an interactive, sophisticated data dashboard with just a few lines of Python code. No JavaScript or HTML knowledge required.</li><li><strong>Fast Prototyping</strong>: Streamlit is perfect for rapid prototyping. It allows for quick iteration and real-time feedback, which is vital for data exploration and model building.</li><li><strong>Interactivity</strong>: Streamlit’s components and widgets make it easy to create interactive applications, enhancing the user experience and enabling more in-depth data exploration.</li><li><strong>Deployment</strong>: Deploying a Streamlit app is relatively easy with options like Streamlit Sharing and Streamlit for Teams.</li></ul><h3>Conclusions</h3><p>Streamlit is a fantastic tool that democratizes the process of building data dashboards and web applications. While it has a few limitations, its ease of use, rapid prototyping capabilities, and interactivity make it a preferred choice for many data professionals. Whether you’re a data scientist wanting to showcase your latest model, a business analyst looking to share insights, or a researcher looking to visualize your findings, Streamlit can help you bring your data to life in an interactive, user-friendly way.</p><p>Finally, have a look at <a href="https://streamlit.io/gallery">Streamlit’s App Gallery</a> to play around with the beautiful demo dashboards available.</p><h4>Suggested Readings</h4><p>Here is what helped me during these years/months, in case you want to dive into Streamlit or Data Visualization in general:</p><ul><li><a href="https://amzn.to/421PefP"><strong>Data Visualisation: A Handbook for Data Driven Design</strong></a></li><li><a href="https://amzn.to/3OF2DXX"><strong>Web Application Development with Streamlit</strong></a></li><li><a href="https://amzn.to/3oxukYa"><strong>Interactive Data Visualization with Python</strong></a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1aa49e984ee6" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>