Nuno Bispo (aka Developer Service) (@DevAsService) header
Nuno Bispo (aka Developer Service) (@DevAsService) profile picture

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

Netherlands
Joined July 2021
Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)Photo by Nuno Bispo (aka Developer Service) (@DevAsService)
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.
4
363
There’s a kind of engineering skill that rarely appears on a CV: knowing what not to automate. AI makes almost everything feel automatable, and the temptation is to let the model handle each new decision simply because it can. But every decision handed to a model is a decision you can no longer fully explain, test exhaustively, or guarantee. The teams I’d trust most draw that line deliberately. They let the model draft, summarise, classify, and suggest, and they keep a human or a plain piece of code in charge of anything that moves money, deletes data, or speaks to a customer in the company’s name. That isn’t timidity. It’s an honest account of where being wrong is cheap and where it isn’t. Capability will keep growing, and the line will keep moving. The skill is in knowing, at any given moment, where it currently sits, and being able to say why. #SoftwareEngineering #AI #TechLeadership #CTO #Python
17
The best compliment an AI agent can get in production is that nobody talks about it. No Slack threads about weird outputs, no surprise on the monthly bill, no one asking “wait, did something change”? Getting there is unglamorous work. It means defining exactly what a valid output looks like and rejecting everything else. It means running evals on every change instead of trusting a few manual tries. It means knowing what a normal day costs, so an abnormal one stands out. And it means having a rollback you’ve actually practiced. None of it makes a good demo, which is why most agent content skips it. Production AI Agents with PydanticAI is about that part of the work: the typed contracts, the evals, the observability, and the rollout discipline that turn an exciting prototype into something quietly reliable. Free sample chapters: leanpub.com/production-ai-ag… #PydanticAI #LLMOps #AIEngineering #PythonEngineering
9
6
94
Three things I check for scope bugs in every Python code review: 1. Any function that both reads and assigns the same name. If a variable is assigned anywhere in the function, Python treats it as local everywhere in that function. Read it too early and you get an UnboundLocalError. 2. Any lambda or inner function created inside a loop. Closures capture the variable, not its value, so every one of them sees whatever the loop variable holds when they finally run. 3. Any global or nonlocal keyword. Sometimes it's the right tool. Often it's a sign that state should be passed in explicitly or moved into a class. None of these are exotic. All of them regularly slip past reviewers who haven't internalised how Python resolves names. I wrote all of this up in a free Python Scope Guide: the LEGB rule, closures, late binding, and global vs nonlocal, with examples you can run. 🎁 Free: python-variable-scope.develo… #Python #CodeReview #SoftwareEngineering #PythonDevelopment
18
A pattern that quietly causes trouble in Python AI integrations is trusting whatever the model returns when it’s asked to call a tool or fill in arguments. The model proposes a function call with parameters, and the code executes it as written. That works until the model invents a field, passes an ID that doesn’t exist, or supplies a value outside the range your function was ever designed for. The fix is to treat tool arguments as untrusted input, exactly as you would data from a web form. Validate them against a strict schema before anything runs, check that referenced records actually exist and belong to the current user, and enforce limits in your own code, such as maximum amounts, allowed actions, and rate caps. If validation fails, return a clear error to the model so it can correct itself, rather than letting a malformed call reach your database or an external API. The principle is the same one that applies everywhere else in a backend: the boundary between a component you don’t control and your own systems is where the checks belong. A model is just another component on the wrong side of that boundary. #Python #AI #PydanticAI #Security #SoftwareEngineering
13
Your support team is spending hours on CSV imports that fail with "something went wrong". If your product lets customers upload data, you've seen this. A customer exports a spreadsheet from their old tool and imports it into yours. Row 4,812 has a date in the wrong format, so the import fails. Or worse, it succeeds and quietly loads a wrong value. The customer opens a ticket, support escalates it to an engineer, and the engineer spends an hour finding one bad cell. Multiply that by every customer onboarding. Imports are often the first thing a new customer does with your product, so they're also the first impression you make. Validating each row against a defined schema fixes most of this. The import either succeeds or returns a report listing the row number, the column, the value it found, and what it expected. Customers fix their own files. Support stops being a debugging service, and engineers stay out of the loop. The same pattern covers webhooks, partner feeds, and any other data that arrives from outside your control. You can't clean up other people's data, but you can tell them exactly what to fix. Practical Pydantic covers how to build this kind of validation for Python systems, including error reporting your users can act on. 👉 leanpub.com/practical-pydant… #EngineeringLeadership #SaaS #ProductEngineering #DataQuality #Python
1
1
56
You don’t need a VPS to run a script once an hour. You probably already have a scheduler, a clean Linux machine, and a secrets store sitting in your GitHub account. A lot of side projects need the same small thing: run a script on a schedule. Pull some data from an API every hour. Render a chart every morning. Ping a service every five minutes. The usual answer is a $5 VPS with a crontab, and that works, until you have to patch it, monitor it, and remember what you installed on it two years ago. GitHub Actions can do the same job with no server to maintain. A scheduled workflow gives you a fresh Ubuntu machine on a cron schedule, with Python preinstalled, encrypted secrets, logs, and failure notifications. For public repositories it is free, and for private ones the free allowance goes further than you might expect. In this article, you’ll build two real examples: - A data collection job that fetches readings from an API and stores them in a cloud Postgres database. - A dashboard renderer that draws a chart as a 1-bit image sized for an e-ink screen, which a small ESP32 device downloads whenever it wakes up. developer-service.blog/stop-… #Python #GitHub #Workflow #VPS #Neon #Postgres
1
46
A useful question for any team running an AI feature is what happens to the system when its owner is unavailable for a week. Not gone, just unavailable: on holiday, ill, or pulled onto another project. In many teams the honest answer is that small problems wait, changes freeze, and everyone hopes nothing breaks until that person is back. The feature is running, but it is effectively unsupervised. That isn’t a staffing failure so much as a design one. Systems that depend on one person’s memory tend to have no runbook, no documented fallback, and alerts that go to a single inbox. The risk stays invisible while things are calm, then shows up all at once on the one week it matters, usually at the least convenient moment. If your AI feature has a single point of failure with a name and a calendar, it’s worth fixing that before the calendar decides for you. #AI #CTO #TechLeadership #SoftwareEngineering #Python
1
1
46
Experienced engineers tend to get quieter about certainty over time. Early in a career, confidence comes from knowing the answer. Later, it comes from knowing how often your own answers have been wrong, and building habits that catch the misses before anyone else does. That shift matters more with AI systems than with conventional software, because the failure modes are less obvious and the feedback is slower. A system can look fine for weeks while quietly drifting from what you intended. The engineers who handle this well aren’t the most certain ones. They’re the ones who’ve learned to treat “it seems fine” as a hypothesis rather than a conclusion. If I could change one thing about how teams ship AI features, it would be replacing “are we sure this works?” with “how would we know if it stopped?” The second question has an answer you can actually build. 🔍 If you don’t have a good answer to that second question yet, that’s a conversation worth having => developer-service.blog/work-… #SoftwareEngineering #AI #TechLeadership #CTO #Python
1
12
An AI agent looks like a chat interface, but operationally it behaves like a distributed system. It depends on a remote service you don’t control. It has variable latency and occasional timeouts. It retries on failure, sometimes in ways that multiply cost. And it can return something that looks like success while being subtly wrong. Engineers already know how to handle that: contracts at the boundaries, tests that catch regressions, budgets and alerts, staged rollouts, and a plan for when things degrade. What’s missing is applying those habits to agents, because most agent tutorials stop at the point where the model returns a response. Production AI Agents with PydanticAI picks up where those tutorials end. You build a GitHub issue triage assistant and give it the same treatment as any service you’d put on call: typed output contracts, eval suites in CI, cost and latency observability, canary rollouts, and a runbook. Free sample chapters: leanpub.com/production-ai-ag… #PydanticAI #LLMOps #AIEngineering #PythonEngineering
4
2
56
A question I keep getting from Python developers: "Why does my function see a variable I never passed in, but crash when I try to change it?" It's a great question, because it points at exactly how Python thinks about names. Reading a variable is easy. Python searches Local, then Enclosing, then Global, then Built-in, and uses the first match. But the moment you assign to that name inside a function, Python decides it's local for the entire function. Reach for it before the assignment and you get an UnboundLocalError, even though a perfectly good global exists. Two rules, one confusing symptom. And once you've seen it explained clearly, you can't unsee it. That's the kind of thing I cover in my free Python Scope Guide: LEGB, closures, late binding, and global vs nonlocal, with examples you can run and break yourself. 🎁 Free: python-variable-scope.develo… What's the scope bug that got you? Tell me in the comments. #Python #PythonTips #SoftwareEngineering #LearnPython
1
22
A habit that saves a lot of pain in Python AI integrations is pinning your model version explicitly instead of pointing at a floating alias. Aliases like “latest” are convenient, but they mean the behaviour of your application can change on the provider’s schedule rather than yours. Outputs shift slightly, formatting drifts, a prompt that was carefully tuned starts behaving differently, and nothing in your own repository changed to explain it. The fix is to treat the model identifier as configuration you control. Pin a specific version, record it alongside every logged call, and upgrade deliberately: run your test cases against the new version, compare outputs, and only then switch. When something does change in production, you can immediately rule out the model as the cause, or confirm it, instead of guessing. It’s a small discipline, but it turns model upgrades from something that happens to you into something you schedule, test, and roll back if needed. #Python #AI #LLM #SoftwareEngineering #DevOps
1
34
The dashboard was wrong for three weeks before anyone noticed. A source system started sending revenue in cents instead of dollars. Nothing crashed. The pipeline loaded the rows, the charts updated, and the numbers looked plausible enough that nobody questioned them. Meanwhile the leadership team made a hiring decision based on them. Analytics pipelines fail quietly because they're built to be tolerant. A null becomes zero. A string that doesn't parse gets skipped. A duplicated batch doubles a total. The pipeline reports success each time, and the damage only shows up when someone compares the dashboard to the bank account. The cost goes beyond the bad decisions made in the meantime. Once people catch one wrong number, they stop trusting the others, and your data team spends weeks proving what was right instead of building anything new. Validating records as they enter the pipeline changes that. Define what a valid row looks like, quarantine the ones that don't match, and alert on the count. A unit change then shows up as a spike in rejected rows on day one, with the exact field and value attached. Practical Pydantic covers how to build that validation layer for Python data pipelines and the services that feed them. 👉 practical-pydantic.com/ #EngineeringLeadership #DataEngineering #DataQuality #TechStrategy #Python
4
3
75
Most AI features get their first real security review after something goes wrong, usually when a customer asks a question in a procurement questionnaire that nobody on the team can answer confidently. Where does user data go when it's sent to the model? Is it retained by the provider? Who on the team can see prompts and responses in the logs? These are reasonable questions, and the awkward part is that the honest answer is often "we'd have to check". That moment is expensive because it usually arrives attached to a deal or a renewal, which means the review happens under pressure, on someone else's timeline. Teams that have already mapped their data flows and access controls answer in an afternoon. Teams that haven't can lose weeks, and sometimes the contract. If you couldn't answer those questions today without a scramble, it's better to find the gaps on your own schedule than a customer's. Let me help you get that clarity => developer-service.blog/work-… #AI #CTO #TechLeadership #SoftwareEngineering #Python
1
21
There's a moment in most AI projects when someone says lets just get it working first, and well make it robust afterwards. It sounds sensible, and sometimes it is. The trouble is that afterwards almost never arrives on its own. The feature starts earning attention, the roadmap fills up, and the robust version quietly becomes a project nobody has the time or the mandate to start. What I've noticed is that the teams who do get to robust aren't the ones who found more time. They're the ones who decided, early and explicitly, which two or three things would never be deferred: secrets handled properly, failures visible, outputs validated. Everything else could be rough. Those few things couldn't. Its a much smaller promise than well make it production ready later, which is exactly why it tends to get kept. #SoftwareEngineering #AI #TechLeadership #CTO #Python
22
🚨 PHP2Shell: if you run PHP anywhere, patch today. On Oct 21, PHP shipped emergency releases for two critical flaws (CVE-2026-109618 and CVE-2026-109619). Unauthenticated remote code execution, rated CVSS 9.2 by the PHP team. The scope is wide: → PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed are all affected → Nearly every version back to 5.4 is exposed to at least one of the issues → WordPress, Drupal, Magento, Joomla and Laravel sites are exposed if the PHP underneath is vulnerable Fixed in: 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Minimal backports exist for 7.4, 8.0 and 8.1, or you can use your distro or LTS vendor’s package. Updating is the only complete fix. The published settings reduce exposure to specific attack paths, but the PHP team is clear that they don’t make an install safe. One more thing to check after patching: the patched runtime can kill a worker immediately at its hard memory limit, bypassing normal shutdown handlers. Test your app under memory pressure. “We’re a Python/AI shop, this doesn’t affect us.” Are you sure? Count the marketing WordPress site, the old admin panel, the vendor container nobody has touched in two years. The real lesson from PHP2Shell isn’t about PHP. It’s that most teams can’t answer “what are we actually running in production?” in under an hour. That’s exactly what I help with. I work with CTOs and engineering leads at AI/Python teams who ship fast and want to be sure it’s secure, observable and maintainable: 🔹 Architecture Call: a focused session on your biggest risk 🔹 AI Code Health Check: a fast review of the code your team (and your AI) is shipping 🔹 Production Readiness Audit: a full inventory of what runs and where it can break 🔹 Rescue & Stabilise Retainer: for when something is already on fire If this week made you wonder what else is running in your stack, let’s talk : 👉 developer-service.blog/work-… #PHP #CyberSecurity #DevSecOps #Python #SoftwareArchitecture
194
A one-line prompt tweak can change the behavior of an agent more than a thousand-line refactor. But in most codebases, the prompt change gets a quick glance and a thumbs up, while the refactor gets a full review and a test run. That mismatch is where a lot of agent incidents start. Someone adjusts the wording to fix one annoying edge case, it looks harmless in the diff, and three days later the output distribution has shifted in ways nobody can trace back to a specific change. The fix is to treat prompts, models, and output schemas as versioned code that has to pass the same gates as everything else: a typed contract the output must satisfy, an eval suite that runs on the pull request, and a canary stage before the change reaches everyone. Thats the approach in Production AI Agents with PydanticAI, where you build a GitHub issue triage assistant chapter by chapter and wire each of those gates into the repo as you go. Free sample chapters: leanpub.com/production-ai-ag… #PydanticAI #LLMOps #AIEngineering #PythonEngineering
3
1
1
45
If I could pin one mental model above every Python developer's desk, it would be this: Python resolves a name by searching four places, in order, and stopping at the first match. 1. Local — inside the current function 2. Enclosing — any outer functions wrapping it 3. Global — the module level 4. Built-in — names like len, print, range That's LEGB. Four layers, one direction, zero exceptions. Almost every confusing scope bug I've seen comes down to a developer assuming Python searched somewhere it didn't, or stopped somewhere they didn't expect. Shadowed names. Closures capturing a variable instead of a value. UnboundLocalError from a single assignment lower in the function. The model is simple. Applying it under pressure, in real code, is the skill. That's why I wrote a free Python Scope Guide: LEGB in depth, closures, late binding, and global vs nonlocal, with practical examples you can run yourself. 🎁 Free: python-variable-scope.develo… #Python #PythonTips #SoftwareEngineering #LearnPython
1
31
One habit that makes Python AI integrations much easier to live with is keeping a small set of real test cases that you run against every prompt or model change. Not a full evaluation framework, just fifteen or twenty representative inputs with the outputs you’d consider acceptable, including a few awkward edge cases you’ve already been bitten by. Without that, every change is judged by eyeballing two or three examples, and regressions only show up when a user finds them. The setup is simple. Store the cases in a file, run them through your actual pipeline, and compare the results against expectations using properties rather than exact string matches: does the output parse, does it contain the required fields, is the classification one of the allowed values, is the length within bounds. Add a case every time something goes wrong in production, and the suite becomes a record of everything your system has already learned the hard way. It takes an afternoon to build and changes how confident you can be in a prompt tweak or a model upgrade, which for most teams happens far more often than they planned for. Need help setting it up? Then developer-service.blog/work-… #Python #AI #Testing #LLM #SoftwareEngineering
16
When a business rule lives in fourteen places, it will be wrong in at least one. Take something as small as how your system treats an email address, a price, or a phone number. One service trims whitespace and lowercases. Another doesnt. A third rejects plus signs. Nobody chose these differences. They built up as different people copied slightly different checks into different files. Then a customer cant log in, or an invoice is off by a cent, and someone spends a day finding out which version of the rule was running. Pydantic's annotated types let you define a rule once and reuse it everywhere. You declare what a valid email or a valid money amount looks like in a single place, and every model that uses that type gets the same behavior. When the rule changes, say a new rounding policy or a stricter ID format, its one edit and one review. The change reaches every service that depends on it. For a team thats growing, that matters more than it sounds. New engineers don' t have to learn which version of the rule is the real one, and your definition of valid data has one owner. Practical Pydantic covers how to build these reusable types into Python systems, along with the validation patterns around them. 👉 leanpub.com/practical-pydant… #EngineeringLeadership #TechStrategy #SoftwareArchitecture #ProductEngineering #Python
26