Nuno Bispo (aka Developer Service)

5.8K posts

Nuno Bispo (aka Developer Service) banner
Nuno Bispo (aka Developer Service)

Nuno Bispo (aka Developer Service)

@DevAsService

Solutions Architect · Senior Python & AI Engineer · AI Audits · Helping teams fix what they shipped too fast

Netherlands Katılım Temmuz 2021
631 Takip Edilen472 Takipçiler
Sabitlenmiş Tweet
Nuno Bispo (aka Developer Service)
I'm Nuno Bispo, a Senior Software Engineer and Solutions Architect with 15+ years building Python systems, AI integrations, and production backends. I write for Real Python and Unstract. I build and ship hardware. I've seen what breaks in production and what doesn't. I take on a small number of advisory engagements with teams that are serious about getting their Python and AI stack right.
English
0
0
0
35
Nuno Bispo (aka Developer Service)
Code reviews reveal a lot about a developer's understanding of Python. One of the most common gaps I see - and across all experience levels - is scope. Not because developers are careless. But because Python's name resolution rules are implicit. The language never forces you to learn them. You can write Python for years and still carry blind spots that surface only under specific conditions. Until they surface in production. I put together a free guide specifically for developers who want to eliminate that blind spot: - The LEGB rule explained with precision, not hand-waving - How Python handles name resolution in nested functions and closures - The global and nonlocal keywords - mechanics, use cases, and red flags - Scope antipatterns that pass code review and cause bugs anyway Solid foundations make better engineers. This is one of them. …variable-scope.developer-service.blog #Python #CodeReview #SoftwareEngineering #PythonDevelopment
English
0
0
0
14
tazko
tazko@tazkoosh·
@DevAsService the validation layer is where the expensive expertise lives. knowing what the output is supposed to look like requires having seen enough wrong ones to recognize the difference. not in the prompt.
English
1
0
1
8
Nuno Bispo (aka Developer Service)
Your AI feature shipped. Your validation layer didn't. It's a common pattern. The team moves fast to get an LLM integration out the door. The model works. The demo looks great. The pipeline goes live. What doesn't ship is the layer that checks whether the AI's output is actually usable before it touches the rest of your system. The assumption is that the model is reliable enough. And it usually is, until it isn't. A response in an unexpected format. A missing field the downstream service didn't anticipate. A confidence score that should have triggered a fallback but didn't, because nothing was checking. These aren't model failures. They're integration failures. And they're expensive in a specific way: they're silent. The system doesn't crash. It just produces wrong results, quietly, until someone notices. The fix isn't complicated. It's a validation layer between your AI output and the rest of your application, one that defines what a valid response looks like, rejects or flags anything that doesn't match, and gives your team a single place to update when the model's behaviour changes. Teams that build this layer before they need it spend less time firefighting and more time iterating. Teams that skip it tend to rebuild it later, under pressure, after something has already gone wrong. That's the real cost of skipping validation in AI pipelines. Not the failure itself, the timing of when you fix it. Practical Pydantic covers how to build this layer in Python, including patterns specific to LLM output validation and structured AI responses. leanpub.com/practical-pyda… Ship the AI feature. Ship the validation layer with it. #EngineeringLeadership #TechStrategy #SoftwareArchitecture #AIEngineering #ProductEngineering
English
1
0
0
18
Nuno Bispo (aka Developer Service)
Your Python script finished. Or did it crash? You won't know until you check the logs. Or until something downstream breaks. There's a better way. ntfy.sh sends a push notification to your phone with a single HTTP call from any Python script. No account. No SDK. Just this: import requests requests.post( "ntfy.sh/your-topic", data="Backup completed successfully", ) I use it for: - AI pipeline completions and failures - Django cron job alerts - ESP32 sensor threshold breaches - Long-running script monitoring Five minutes to set up. Zero excuses for silent failures in production. #Python #DevOps #AI #MicroPython #SoftwareEngineering
English
0
0
0
12
Nuno Bispo (aka Developer Service)
I reviewed an AI codebase last week. The API key was in the repository. The repository was public. It had been there for eight months. Nobody noticed. Or nobody said anything. Either way, that's not a technical problem. That's a process problem wearing a technical mask. The scariest codebases aren't the messy ones. They're the ones where nobody is looking. #Python #AI #CyberSecurity #SoftwareEngineering #AIEngineering
English
0
0
1
19
Nuno Bispo (aka Developer Service)
If you've ever asked "why does this variable have that value?", this is for you. Python's scoping rules are deterministic and well-defined. But without knowing them explicitly, even experienced developers find themselves guessing instead of reasoning. That gap between guessing and reasoning is what makes the difference in a code review, a debugging session, or a production incident. I've compiled a free guide that closes that gap: → A precise breakdown of the LEGB rule with annotated examples → How closures capture and retain values across function calls → The mechanics behind global and nonlocal declarations → Scope-related antipatterns common in real Python codebases No padding. No beginner hand-holding. Written for developers who want to reason about their code with confidence. …variable-scope.developer-service.blog #Python #PythonDeveloper #SoftwareCraft #CodeQuality
English
0
0
0
21
Nuno Bispo (aka Developer Service)
At some point, every internal tool, CLI utility, or developer script needs to remember something between runs. A list of environments. A job queue. A cache of API responses. A set of user preferences. The default response is to reach for a database. Set up SQLite, write a schema, maybe add an ORM. That's fifteen minutes of infrastructure for a problem that might not warrant it, and fifteen minutes that turns into an hour once you factor in migrations, connection handling, and test fixtures. There's a narrower tool for this class of problem. It's called TinyDB. developer-service.blog/your-python-to… #TinyDB #Python #Database #JSON
English
0
0
0
31
Nuno Bispo (aka Developer Service)
Most teams don’t lack observability. They lack fast reaction. Dashboards don’t wake anyone up. Logs don’t escalate themselves. That gap is where incidents get expensive. A simple fix: use ntfy.sh as the last-mile alert layer. Keep your stack (Prometheus, Grafana, etc.). Just make sure critical signals reach people immediately. curl -d "Model drift detected: 12%" ntfy.sh/your-topic Observability tells you what happened. Notifications decide whether you act in time. Most teams optimize the first and neglect the second. #observability #devops #sre #aiengineering #mlops #incidentmanagement
English
0
0
0
25
Nuno Bispo (aka Developer Service)
Bad data doesn't announce itself. It just quietly breaks things downstream. A missing field here. A type mismatch there. A null where your code expected a string. Individually, small problems. At scale, across multiple services, external APIs, and async pipelines, they become incidents. The typical response is to add more logging, more error handling, more defensive checks scattered across the codebase. Each one reasonable. Collectively, a maintenance burden that grows faster than the team does. The more durable fix is to stop treating validation as an afterthought and make it structural. Define what valid data looks like once, at the boundary where it enters your system, and let that definition do the work everywhere else. That's not a new idea. But most teams don't do it consistently, because the tooling used to make it awkward. With Pydantic, it isn't anymore. Teams that adopt this pattern report fewer data-related incidents, faster debugging when something does go wrong, and significantly less time spent on the class of bugs that are hardest to reproduce: the ones that only appear in production, with real data, under real load. That's a risk and cost argument, not a technology argument. The technology is just what makes it practical. Practical Pydantic is a short, focused book on applying this approach in real Python systems, APIs, pipelines, and production services. Written for teams that are already building, not starting from scratch. 👉 leanpub.com/practical-pyda… The bugs that cost the most are the ones your code didn't know to catch. #Pydantic #Python #Data #Validation #Risk #Cost
English
0
0
0
30
Nuno Bispo (aka Developer Service)
Pydantic is helpful by default. Sometimes too helpful. When you pass "42" into an int field, Pydantic doesn't complain, it just converts it. String becomes integer. No error. No warning. That's type coercion, and it's on by default. For many use cases, it's exactly what you want. Parsing a CSV, reading query parameters, handling form data, coercion saves you a lot of manual conversion. But in some systems, silent conversion is the last thing you want. If your internal services are passing "42" where they should be passing 42, that's a bug, not a feature. Coercion hides it. Strict mode surfaces it. Now the model refuses to guess. You get an error immediately, at the boundary, with a clear message. The contract is enforced, not worked around. Strict mode isn't the right default for every project. But knowing it exists, and when to reach for it, is what separates a model that accepts data from one that actually validates it. 👉 leanpub.com/practical-pyda… Helpful by default. Strict when it matters.
Nuno Bispo (aka Developer Service) tweet media
English
0
0
0
25
Nuno Bispo (aka Developer Service)
You've been there. The hardware works. The sensors are wired up. And somewhere inside main.py a print() is faithfully reporting voltage every second into a serial terminal that nobody will ever open again. The gap between "working prototype" and "something you'd actually show someone" is often just a few hundred lines of web code. In my latest article, I wired an INA219 power monitor to an ESP32-C3 Super Mini and served a live battery charge dashboard directly from the device using Microdot — any browser on the same network can open it. No gateway. No app. No cloud. But the hardware is just the excuse. The real lesson is the architecture: - sensor.py owns hardware reads, returns plain dicts - web.py owns the HTTP contract — routes, status codes, content types - The browser polls a tiny JSON endpoint and renders That split keeps your MicroPython web apps maintainable as they grow. And it works for any sensor you'd wire to a microcontroller: temperature, fuel gauges, motion detectors. developer-service.blog/serving-a-live… #MicroPython #ESP32 #Python #INA219 #TP4056
English
0
0
0
15
Nuno Bispo (aka Developer Service)
Python scope is one of those topics that separates developers who debug fast from those who don't. The language gives you no warning when a variable resolves to an unexpected value. It simply executes, returns a result, and moves on. Tracking down the source of that behaviour - without a solid mental model of how Python resolves names - can cost hours. The LEGB rule isn't complicated. But it's rarely taught with the depth it deserves. I wrote a free guide to change that: → How Python's name resolution actually works under the hood → The LEGB lookup chain with concrete, practical examples → Enclosing scopes and closure behaviour explained clearly → When global and nonlocal are appropriate - and when they signal a design problem → The scope patterns most likely to introduce silent bugs in real codebases Download it free: …variable-scope.developer-service.blog #Python #SoftwareEngineering #PythonDevelopment #BackendDevelopment
English
0
0
0
24
Nuno Bispo (aka Developer Service)
Most Python developers hit a wall the first time they try to pass parameters to a decorator. @login_required works fine. But @retry(times=3)? Suddenly nothing makes sense. The good news: parametrized decorators aren't a different concept. They're just one extra function layer on top of what you already know. In my latest article I break down: → The three-layer pattern: factory → decorator → wrapper → Why the extra layer is forced by how Python evaluates things → How closures keep your params alive on every call → Real decorators you can ship: @retry, @timer, @require_role → Stacking order and how to debug a broken stack Once it clicks, you'll spot the pattern everywhere — Django, FastAPI, Tenacity all use it. 🔗 Link in the comments #Python #SoftwareDevelopment #Programming #PythonTips
English
1
0
0
20
Nuno Bispo (aka Developer Service)
Most Python bugs I've reviewed in production weren't logic errors. They were scope errors. The kind where a variable holds an unexpected value because Python's lookup rules resolved it somewhere the developer didn't anticipate. No exceptions raised. No obvious red flags. Just incorrect behaviour at runtime. After years of writing and reviewing Python code, I've seen this pattern repeat across experience levels - junior developers and senior engineers alike. Understanding Python's scoping model isn't advanced knowledge. It's foundational. And it's one of the most under-taught topics in the ecosystem. I put together a free guide that covers it properly: → The LEGB rule and how Python resolves variable names → Closures, enclosing scopes, and why they behave the way they do → The right (and wrong) use cases for global and nonlocal → Common scope-related bugs and how to identify them quickly If you write Python professionally, this is 15 minutes well spent. Free download: …variable-scope.developer-service.blog #Python #SoftwareEngineering #PythonDevelopment #CodeQuality
English
0
0
0
15
Nuno Bispo (aka Developer Service)
Your app has secrets. Don't scatter them across the codebase. Most Python projects manage configuration with raw os.getenv() calls, which are sometimes sprinkled across files, untyped, unvalidated. You only discover a missing variable when the app crashes in production. BaseSettings from Pydantic fixes this at the root. One class. That's your entire configuration layer. Pydantic reads from environment variables automatically, coerces types, and raises a clear error at startup if anything required is missing. And because it's just a Pydantic model, you can add validators, nested settings, and per-environment overrides - all in the same place. One import. One instance. One place to look when something's misconfigured. This pattern alone justifies adding pydantic-settings to any serious Python project. It's covered in depth in Practical Pydantic, along with patterns for managing settings across environments, secrets, and production services. 👉 leanpub.com/practical-pyda… Configure once. Trust everywhere. #Python #Pydantic #Settings #Security
Nuno Bispo (aka Developer Service) tweet media
English
1
0
0
16
Nuno Bispo (aka Developer Service)
Your build server is running out of space. You run df -h. 94% full. Great. So you du -sh your way through directories like it's 2005, mentally adding up numbers, until you finally find the 6 .venv folders nobody cleaned up. There's a better way — and building it yourself is half the point. In my latest article, I walk through building pydusk: a terminal disk usage analyzer in Python, inspired by ncdu. Keyboard-driven, non-blocking, with a delete confirmation flow and a clean TUI — all in a single file with two dependencies. Things worth stealing from this project even if you never run it: → Why os.scandir beats os.walk for disk traversal → Textual's @work(thread=True) pattern for background tasks → ModalScreen[T] + dismiss() for confirmation dialogs Full source on GitHub. Article linked in the comments. #Python #Textual #CLI #OpenSource #Developer
English
1
0
1
34