Author: Angelo Geant Gaviola

  • Learning Python by Doing: A Hands-On Guide for Active Learners

    Learning Python by Doing: A Hands-On Guide for Active Learners

    Remember the last time you tried to learn something from a textbook, only to realize weeks later that you couldn’t actually do anything with that knowledge?

    Maybe you highlighted every other sentence, took good notes, and still drew a blank when it came time to apply what you’d learned.

    If you’re nodding along, you’re not alone and you’ve probably discovered something important about yourself: you’re a learn by doing person.

    The good news? Python is practically made for hands-on learners. Unlike subjects that require years of theory before practice, Python lets you write your first useful program on day one.

    But here’s the challenge: with thousands of tutorials, courses, and resources available, how do you find the ones that actually let you build instead of just watch?

    Let me show you exactly how to learn Python through action, experimentation, and real projects that matter.

    Why Learning by Doing Actually Works

    Before we dive into resources, let’s talk about why this approach is so effective. When you learn by doing, you’re engaging in what educators call “active learning.”

    Your brain doesn’t just passively absorb information. It creates neural pathways through problem-solving, debugging, and the satisfying moment when your code finally works.

    Think about it: would you rather spend three hours watching someone else cook, or one hour actually making a meal (even if you burn the garlic)?

    The second option teaches you more because you’re dealing with real problems: the pan’s too hot, you forgot to chop the onions first, the timing is trickier than it looked.

    Python is the same way. Every error message is a lesson, every bug you fix makes you stronger.

    Plus, when you build something actual, even something simple like a dice roller or a to-do list.

    You get instant proof of your progress. That motivation is gold when you’re learning something new.

    Two Paths for Hands-On Python Learning

    There are two main approaches to learning Python by doing, and both work brilliantly. The key is choosing the one that matches your personality.

    Path 1: Interactive Courses with Built-In Practice

    Some people thrive with a bit of structure. A roadmap that tells them what to learn next while still keeping their hands on the keyboard. Interactive coding platforms are perfect for this.

    Unlike traditional video courses where you watch passively, these platforms put you in the driver’s seat from minute one.

    Boot.dev takes you from complete beginner to building real backend systems through gamified lessons. You’re not just reading about functions; you’re writing them to solve actual challenges.

    Each module builds on the last, and you’re coding in every single lesson.

    The gamification aspect (earning XP, leveling up) might sound gimmicky, but it’s surprisingly effective at keeping you engaged during the inevitable frustration moments.

    Codecademy offers a more traditional course structure but with a critical difference: the entire experience happens in their browser-based code editor.

    When they teach you about lists, you immediately practice creating and manipulating them. When they introduce APIs, you make real API calls right there in the lesson.

    It’s like having training wheels that gradually come off as you progress.

    CodinGame takes a completely different approach it teaches you Python through games and puzzles. You might write code to control a robot through a maze or solve optimization challenges.

    It’s fantastic if you need that extra layer of fun to stay motivated, and it sneakily teaches you algorithmic thinking along the way.

    When to choose this path: If you like having clear milestones, appreciate some guidance on what to learn next, or tend to get overwhelmed by too many choices.

    Path 2: Project-Based Learning (Jump Into the Deep End)

    Now, if you’re the type who learns best by figuring things out as you go, who gets excited by a challenge and enjoys the detective work of finding solutions.

    Project-based learning might be your sweet spot.

    This approach flips traditional learning on its head. Instead of learning Python concepts and then building something, you decide what to build first and learn the concepts as you need them.

    Want to create a web scraper? You’ll learn about requests, HTML parsing, and file handling because your project demands it.

    Practical Tutorials Project-Based Learning is a treasure trove of tutorials where you build complete, functional projects.

    We’re talking about creating your own neural network from scratch, building a web crawler, making a command-line game, or crafting a personal finance tracker.

    Each tutorial walks you through building something real while explaining the Python concepts along the way.

    What makes this resource special is its diversity. You can choose projects that align with your interests.

    Love data? Build a data visualization dashboard.

    Into gaming? Create a text-based adventure or a simple 2D game.

    Want to automate your life? Build a web scraper or an automated email sender.

    Build Your Own X takes this even further with the philosophy that you only truly understand something once you’ve built it yourself.

    This collection guides you through recreating technologies you use every day: your own Git, your own Docker, your own BitTorrent client, your own text editor.

    These aren’t toy projects, they’re simplified versions of real systems.

    Building them gives you a profound understanding not just of Python, but of how software actually works under the hood.

    Yes, they’re challenging.

    Yes, you’ll get stuck. But that’s exactly where the learning happens.

    When to choose this path: If you’re self-motivated, don’t mind googling for answers, get energized by challenges, or already have a specific project idea in mind.

    The Bottom Line: Just Start Building

    The beauty of learning Python by doing is that there’s no single “right” path.

    There’s only the path that keeps you coding.

    Whether you thrive with the structured guidance of interactive platforms or prefer diving headfirst into building real projects, both approaches share one critical element: your hands stay on the keyboard.

    Choose the approach that excites you most.

    If you’re unsure, try one for a week and if you are not feeling it.

    Switch to the other. The worst thing you can do is spend weeks researching the “perfect” way to learn while never writing a single line of code.

    Your Next Steps Start Now

    Learning Python by doing isn’t just an effective strategy.

    It’s the most sustainable one.

    When you build things, you stay motivated because you can see your progress.

    When you solve real problems, the knowledge sticks because you earned it through struggle and triumph.

    So here’s my challenge to you: close this tab, pick one resource from this post (just one!), and write your first five lines of code today. Not tomorrow. Not when you have more time. Today.

    Because at the end of the day, the best way to learn Python isn’t through the perfect course or the perfect tutorial.

    It’s through that messy, frustrating, exhilarating process of building something that doesn’t work, then making it work, then making it better.

    Your first project is waiting. What are you going to build?

    Enjoyed this post?

    Here’s the thing: I discover stuff like this all the time. Type quirks. Debugging shortcuts. FastAPI gotchas. Lessons from the real world. And, I share them all in my newsletter.

    Want them delivered to your inbox?

  • How to Actually Learn Python in 2025 (Hint: There’s No “Best” Way)

    How to Actually Learn Python in 2025 (Hint: There’s No “Best” Way)

    “What’s the best way to learn Python in 2025?”

    I get asked this question at least once every encounter with someone who wants to start learning to program. And every single time, I want to give a straightforward answer, some magic course or perfect roadmap that unlocks Python mastery in 30 days. But here’s the truth that nobody wants to hear: there is no best way.

    The question itself is flawed. It’s like asking “What’s the best way to get fit?” when you haven’t decided whether you enjoy running, lifting weights, or playing basketball. The answer completely depends on who you are.

    The One-Size-Fits-All Myth

    We’ve been conditioned to believe that somewhere out there exists the ultimate Python course. The one with perfect reviews, taught by a Stanford professor, with gamified lessons and AI-powered feedback. If we could just find it, learning would be effortless.

    But I’ve watched countless people burn through Udemy courses, abandon Codecademy subscriptions, and give up on thick O’Reilly books, all while convinced they were following the “best” path. The problem wasn’t the resources. The problem was the mismatch between the learning method and how their brain actually works.

    The Three Learning Tribes

    Through years of talking with developers, I’ve noticed that most people fall into three learning tribes. Understanding which one you belong to changes everything.

    The Builders (Learning by Doing)

    If you’re a Builder, reading documentation feels like torture. Watching tutorial videos makes you jumpy. You need to get your hands dirty immediately, breaking things, fixing them, and figuring stuff out through experimentation.

    I’m a Builder. Back in 2018, I stumbled across a 4-hour FreeCodeCamp Python course on YouTube. I didn’t just watch it. I coded along, pausing every few minutes to tinker with the examples. When the instructor built a calculator, I built a tip calculator. When they showed loops, I created a number guessing game.

    Here’s what that first game looked like:

    import random
    
    secret_number = random.randint(1, 100)
    guesses = 0
    
    print("I'm thinking of a number between 1 and 100...")
    
    while True:
        guess = int(input("Your guess: "))
        guesses += 1
        
        if guess < secret_number:
            print("Too low!")
        elif guess > secret_number:
            print("Too high!")
        else:
            print(f"You got it in {guesses} guesses!")
            break
    

    Was it elegant? Absolutely not. But I built it, it worked, and I learned more from those 30 lines than I would have from reading three chapters about control flow.

    If you’re a Builder: Skip the theory-heavy courses. Start with project-based learning. Build a password generator. Create a weather app that scrapes data from a website. Make a bot that texts you daily motivation quotes. The messier, the better.

    The Readers (Learning by Understanding)

    Some people need to understand the “why” before they touch the “how.” If you’re a Reader, you want to see the full picture, understand the underlying concepts, and build a mental model before writing a single line of code.

    Readers thrive with books like “Python Crash Course” or “Automate the Boring Stuff.” They love documentation, written tutorials, and blog posts that explain not just what code does, but why it’s designed that way.

    My friend Alex is a Reader. She spent two weeks reading about Python fundamentals before writing any code. When she finally started coding, though, everything clicked instantly because she’d built such a solid conceptual foundation.

    If you’re a Reader: Invest in quality books and written resources. Don’t feel guilty about spending a week reading before coding. Take detailed notes. Draw diagrams. Create your own documentation. Once you start coding, you’ll move faster than everyone else because you’ll actually understand what’s happening under the hood.

    The Watchers (Learning by Observing)

    Watchers learn best when someone shows them how it’s done. They need to see the process, hear the explanations, and follow along with an instructor who can demonstrate techniques in real-time.

    Video courses, live coding sessions, and bootcamps are perfect for Watchers. They benefit from seeing someone else’s thought process, including the mistakes and debugging sessions that books and documentation skip over.

    If you’re a Watcher: YouTube is your goldmine. Channels like Corey Schafer, Tech With Tim, and freeCodeCamp have hundreds of hours of quality Python content. Consider joining a bootcamp or taking a comprehensive video course on Udemy or Coursera. Watch someone build a complete project from start to finish, then recreate it yourself.

    Finding Your Tribe (And It’s Okay to Overlap)

    Most people aren’t purely one type. I’m primarily a Builder, but I still watch videos when I’m learning a completely new concept, and I’ll read documentation when I need to understand something deeply.

    Here’s a quick test: Think about the last time you learned something new, maybe cooking a recipe, assembling furniture, or figuring out a new app.

    • Did you dive right in and figure it out as you went? (Builder)
    • Did you read all the instructions first? (Reader)
    • Did you watch a tutorial or ask someone to show you? (Watcher)

    Your natural instinct tells you everything you need to know.

    Making It Work in Your Actual Life

    Here’s the part nobody talks about: even the perfect learning method fails if it doesn’t fit your lifestyle.

    You have three uninterrupted hours on Sunday mornings? That’s perfect for diving deep into a comprehensive course or building a substantial project.

    You commute an hour each way? Audio courses or podcasts about programming concepts might be your secret weapon.

    The best learning method isn’t just about your learning style. It’s about the intersection of your style and your real-world constraints.

    Your First Steps (Starting Today)

    Enough theory. Here’s what to do right now:

    1. Pick a small project (not a course): Think of something you’d actually use. A budget tracker? A script that renames your messy photo library? A program that reminds you to drink water?
    2. Start building it badly: Don’t research the “right” way. Google as you go. Copy code from Stack Overflow. Make it work first, make it pretty later.
    3. Notice when you’re stuck: Are you stuck because you don’t understand a concept? Read about it. Need to see how something works? Watch a video. Want to just try different approaches? Experiment in code.
    4. Double down on what works: When something clicks, do more of that. If a particular YouTube channel makes sense, binge their content. If you loved building your first project, build three more.
    5. Ignore the guilt: You don’t need to finish that course you bought. You don’t need to read that 800-page book. Learning isn’t about completing resources—it’s about building skills.

    The Real Secret

    Want to know what actually separates people who learn Python from people who buy Python courses? It’s not intelligence, prior experience, or finding the “best” resource.

    It’s simply this: they start building something that matters to them, using a method that fits their brain, on a schedule that fits their life. And they don’t quit when it gets hard.

    So here’s my actual answer to “What’s the best way to learn Python in 2025?”

    Figure out how you learn best. Build something. Start today. Adjust as you go.

    The best way isn’t out there waiting to be discovered. You create it yourself, one line of code at a time.

    Enjoyed this post?

    Here’s the thing: I discover stuff like this all the time. Type quirks. Debugging shortcuts. FastAPI gotchas. Lessons from the real world. And, I share them all in my newsletter.

    Want them delivered to your inbox?

  • Why I Choose Maintenance Work Over New Features (And You Might Too)

    Why I Choose Maintenance Work Over New Features (And You Might Too)

    Imagine this: Your team’s Slack channel lights up with an announcement. “We’re building a brand new feature!” Developers start claiming tickets, excitement buzzes through the air, and everyone wants a piece of the action. Meanwhile, I’m quietly raising my hand for something else entirely. That hideous bug that’s been lingering in the backlog, or the refactoring task everyone’s been avoiding.

    I know what you’re thinking. Who actually prefers maintenance work?

    Well, I do. And before you write me off as some kind of rockstar developer, hear me out.

    About 70% of the time, I actively choose maintenance work over new projects. Not because I lack ambition or creativity, but because I’ve discovered something most developers overlook:

    Maintenance work offers a kind of professional satisfaction that new features simply can’t match.

    The Unexpected Freedom of Low Expectations

    Let’s talk about the elephant in the room, PRESSURE.

    When stakeholders greenlight a new project or feature, they’re not just giving you creative freedom. They’re making an investment, and investments come with expectations. If the company pours $10,000, $50,000, or more into your new feature, you’d better believe there’s a return-on-investment conversation happening in every planning meeting.

    This creates what I call “creative anxiety.” You’re supposed to be innovative, but you’re also supposed to deliver measurable business value. You’re given freedom, but it’s freedom within very specific guardrails. Ship too slowly, and you’re blocking revenue. Ship something that doesn’t gain traction, and suddenly you’re in post-mortem meetings explaining what went wrong.

    Maintenance work flips this dynamic entirely.

    When you’re fixing bugs, refactoring legacy code, or optimizing existing features, expectations are refreshingly straightforward: make it work better. There’s no quarterly revenue target tied to your pull request. No one’s calculating the ROI of a bug fix the same way they scrutinize new feature development.

    This doesn’t mean maintenance work isn’t important. It absolutely is. But it operates under a different kind of pressure. Instead of “will this make us money?” the question becomes “does this make our product more reliable?” That subtle shift changes everything.

    The Freedom to Experiment

    Here’s what this looks like in practice: Imagine volunteering to refactor a complex form flow that’s accumulated years of technical debt. The code is brittle, test coverage is minimal, and every change takes three times longer than it should.

    Because this is “just maintenance,” you have freedom to experiment with patterns you’ve been wanting to try. You can introduce better state management, restructure components for clarity, add comprehensive documentation—things that might get pushback on a high-stakes feature launch.

    The beauty is that you can iterate and improve without someone constantly asking about the business impact. Your success metric is simple: does it work better than before? That simplicity is liberating.

    The Deep Dive: Where Real Expertise Lives

    There’s another reason I prefer maintenance work, and it’s arguably more important: depth of understanding.

    Working on new features often means staying at the surface level. You’re building something fresh, which means you’re focused on the immediate requirements and getting it shipped. You learn the new thing you’re building, but you don’t necessarily learn why the system works the way it does.

    Maintenance work forces you to go deep.

    Understanding the “Why” Behind the Code

    When you’re debugging a production issue or refactoring a legacy module, you don’t have the luxury of ignoring context. You need to understand:

    • Business Rules: Why does this validation exist? What edge case is it protecting against?
    • Historical Decisions: Why was this architecture chosen? What constraints existed at the time?
    • System dependencies: How does this component interact with everything else?

    This deep dive transforms you from someone who just writes code into someone who truly understands the product.

    For example, while fixing what seemed like a simple data inconsistency bug, you might discover an undocumented business rule that’s been embedded in conditional statements for years. Nobody wrote it down it just exists in the code.

    With that knowledge, you can:

    1. Document the business rule properly for the first time
    2. Suggest a simpler implementation that reduces complexity
    3. Identify other places where similar logic should be applied consistently
    4. Save the team weeks of confusion on future features

    You can’t gain this level of insight when you’re only building new things. New features are built on assumptions about how the system works. Maintenance work shows you the reality.

    The Unexpected Career Advantage

    Here’s something nobody tells junior developers: being the person who understands the existing system is incredibly valuable.

    Teams are full of people who want to build new features. They’re much rarer to find developers who can confidently say, “I know exactly why that error occurs, where it’s happening, and how to fix it without breaking three other things.”

    This expertise makes you:

    • The go-to person when things break in production.
    • A better architect because you’ve seen what works and what doesn’t.
    • A valuable code reviewer who catches subtle bugs others miss.
    • A strategic advisor who can estimate effort accurately and flag risks early.

    When New Features Do Call

    Don’t get me wrong I’m not anti-innovation. That remaining 30% of the time, I absolutely love diving into new features. But I approach them differently because of all the maintenance work I’ve done.

    When I do work on something new, I build it with maintenance in mind:

    • Clear documentation because I’ve struggled with undocumented legacy code
    • Comprehensive tests because I’ve debugged too many “it works on my machine” bugs
    • Thoughtful architecture because I’ve refactored too many “we’ll clean this up later” compromises that never got cleaned up

    My maintenance work makes me a better feature developer. And my feature development gives me more empathy for the maintenance work I’ll do later.

    The Question Back to You

    So here’s what I’m curious about: Where do you find your professional satisfaction?

    Are you energized by the blank canvas of a new project, or do you get a rush from finally solving that mysterious production bug? Do you prefer building new systems, or do you love the detective work of understanding existing ones?

    There’s no right answer here. Development teams need both types of people. The innovators who push forward and the maintainers who ensure everything keeps running smoothly.

    But if you’ve never given maintenance work a fair shot, I’d encourage you to volunteer for that next refactoring ticket or bug hunt. You might be surprised at how much you learn, how much creative freedom you actually have, and how satisfying it feels to make something better rather than just making something new.

    After all, in a world where everyone wants to build the next shiny feature, there’s something quietly powerful about being the person who makes sure everything we’ve already built actually works.

    What’s your take? Are you team new-features or team maintenance? Let me know!

    Enjoyed this post?

    Here’s the thing: I discover stuff like this all the time. Type quirks. Debugging shortcuts. FastAPI gotchas. Lessons from the real world. And, I share them all in my newsletter.

    Want them delivered to your inbox?

  • How to save your  afternoon from debugging just because of a type mismatch in Python?

    How to save your afternoon from debugging just because of a type mismatch in Python?

    Recently, someone asked me: “How do I avoid running into type issues in python?”

    The question came after they’d spent an entire afternoon debugging what they assumed was a logic error, only to discover the real culprit was a type mismatch. A function they thought returned a list was actually returning a string, and that single assumption fell into hours of frustration.

    I couldn’t help but laugh, not at them, but with them. Because, I’d been there just weeks before.

    The Problem With Dynamic Typing

    Don’t get me wrong. I love Python’s dynamic typing. It’s one of the reasons Python feels so intuitive and quick to write. You don’t need to declare types everywhere, which makes prototyping fast and code readable.

    But that flexibility comes with a hidden cost.

    Imagine this, You’re reviewing code from a teammate. You see a variable named lst, and naturally assume it contains a list. You write a loop, maybe call .append() or iterate with an index. Everything looks fine.

    Then you run the code and get an error. Turns out, lst was actually a string the whole time. Now you’re diving through multiple files, tracing function calls, and questioning your career choices.

    Sounds familiar?

    Enter Type Hints

    The solution that transformed my workflow: type hints.

    Introduced in Python 3.5, type hints are optional annotations that specify what types your variables, parameters, and return values should be. They look like this:

    def get_user_names(user_ids: list[int]) -> list[str]:
        """Fetch user names from a list of user IDs."""
        return [fetch_name(uid) for uid in user_ids]

    Notice the : list[int] after the parameter and -> list[str] before the colon? Those are type hints telling you exactly what goes in and what comes out.

    Why Type Hints Changed Everything

    1. Bugs caught before runtime – With a static type checker like mypy, type mismatches get flagged before the code even runs. No more surprise errors in production.
    2. Self-documenting code – Instead of digging through function implementations or docstrings, you can see at a glance what types a function expects and returns.
    3. Better IDE support – Modern editors like VS Code and PyCharm use type hints to provide accurate autocomplete suggestions and catch errors as you type.
    4. Easier Refactoring – When you change a function’s return type, your type checker immediately shows you every place that needs updating.

    Conclusion

    Python’s dynamic typing is a feature, not a bug. But type hints give you the best of both worlds: the flexibility of dynamic typing during development and the safety of static typing when you need it.

    If you’re still debugging type errors for hours, give type hints a try. Your future self will thank you.

    And that person who asked me the question? They’re now a type hints user too.

    Enjoyed this post?

    Here’s the thing: I discover stuff like this all the time. Type quirks. Debugging shortcuts. FastAPI gotchas. Lessons from the real world. And, I share them all in my newsletter.

    Want them delivered to your inbox?

  • Solve Your Own Problems: The Developer’s Guide to Creating Useful Tools

    Solve Your Own Problems: The Developer’s Guide to Creating Useful Tools

    A question I frequently hear from fellow developers is: “How do I develop a tool that has concrete use in daily life, one that solves a specific problem or saves time, even if it seems trivial?”

    This question is fantastic because it reveals how eager our community is to create meaningful solutions that help real people. But with so many potential problems to solve, where should you start?

    The Secret: Look Within

    In this world, problems affect everyone. Every single person has their own challenges they’re experiencing and dealing with—your friends, family, peers, and yes, especially yourself.

    And that’s actually wonderful news for developers. Why? Because our job is essentially to solve problems and get paid for it.

    The Value Equation

    Here’s a simple formula I’ve found useful:

    Value = Problem + Working Solution

    This is how our tools increase their value—by effectively addressing actual problems people face.

    Why Solving Your Own Problems Works Best

    So how do we create tools with genuine value in people’s daily lives? The answer is surprisingly simple:

    Look within yourself and ask:

    “What’s a pain in my ass right now?”

    And start from there. 🙂

    The Benefits of Self-Centered Problem Solving

    Solving your own problems comes with significant advantages:

    You are the audience: You instinctively know how valuable the solution is because you experience the problem firsthand

    Immediate feedback loop: You don’t need to wait for external validation—you’ll know immediately if your solution works

    No research needed: You don’t have to spend time understanding someone else’s problem

    Passion: You’ll be more motivated to create something that genuinely helps you

    From Personal Annoyance to Valuable Tool

    Think about some of the most successful tools and apps we use today. Many started because someone was frustrated with an existing process and built something better:

    • Developers created Git because they needed better version control
    • Notion began because its founders wanted a better way to organize their own information
    • Countless productivity apps exist because their creators wanted to manage their own time better

    Getting Started

    1. Document your frustrations: Keep a log of things that annoy you throughout your day
    2. Evaluate solutions: For each problem, consider if technology could make it better
    3. Start small: Build a minimal version that solves just the core issue
    4. Iterate: Use your solution and improve it based on your own experience
    5. Share: Once it works for you, others with similar problems will probably find it valuable too

    Conclusion

    So, my fellow developers, I say to you: SOLVE YOUR OWN PROBLEMS.

    Not only is it the fastest path to creating something useful, but it’s also the most authentic way to build tools that have genuine value in daily life. The best solutions often come from scratching your own itch.

    What problem are you going to solve for yourself today?

    Enjoyed this post?

    Here’s the thing: I discover stuff like this all the time. Type quirks. Debugging shortcuts. FastAPI gotchas. Lessons from the real world. And, I share them all in my newsletter.

    Want them delivered to your inbox?

  • The Facebook ad that saved me from gaming addiction

    The Facebook ad that saved me from gaming addiction

    Back in 2018, I was a young boy with no direction or inspiration for my future. During that time, I drowned myself in games, spending over 10 hours daily at internet cafes.

    I’d go home to eat lunch or dinner for a few minutes, only to rush back to play games.

    For those unfamiliar with internet cafes, they’re spaces filled with computers where people pay to use computers for gaming and other activities, similar to what’s shown in the image.

    Looking back now, I’m amazed at my transformation from a 16-year-old gaming addict to a (somewhat) functional software developer at a startup.

    This change might never have happened if I hadn’t encountered a Facebook advertisement about Santiago Lopez, an ethical hacker from HackerOne who had earned $1 million through bug bounties.

    From that point, it just snowballed. I began learning Python programming, studying networking, virtualization, technical writing, DevOps, server management, and cybersecurity.

    Along the way, I connected with many acquaintances and friends who helped me learn and challenged me to grow.

    I can honestly say I’m grateful to Facebook for showing me that advertisement. Because of it, I embarked on this journey that changed my life.

    Enjoyed this post?

    Here’s the thing: I discover stuff like this all the time. Type quirks. Debugging shortcuts. FastAPI gotchas. Lessons from the real world. And, I share them all in my newsletter.

    Want them delivered to your inbox?