#39 Consistency Beats Accuracy (Part 2)

The bigger your codebase grows, the more important it becomes to stay consistent — in naming things and in how you use features of your programming language. Take input parameters and variables, for example. Is the ID of a Save object sometimes named save_id, other times saveId, and occasionally just id? Is the function to load it called load_save(...), get_save(...), or fetch_save(...)? Or maybe it’s load_save(...) for saves, but get_settings(...) and fetch_tag(...) elsewhere? If so, confusion is only a matter of time. ...

August 8, 2025

#37 Google Requires a New versionCode for Every App Bundle You Publish

When publishing a new version of your Android app through the Google Play Console, you must increment the versionCode in your app’s build.gradle file. This is required even if the versionName (the human-readable version string) stays the same. I found this a bit confusing at first — but the rule is simple: Before you build the bundle you upload to Google Play, make sure you’ve updated the versionCode. If you don’t, your upload will be rejected immediately. ...

August 6, 2025

#33 Mind the Gap — flex-gap!

I use flex-based layouts a lot in the #Angular frontend of poketto.me. But I never realized there’s a neat little property called gap (or flex-gap) that lets you define spacing between flex items directly. For the longest time, I worked around this with clumsy constructs where I’d set margins on child elements — and then unset them on the last child: .container { display: flex; flex-direction: column; .child { margin-bottom: 1rem; &:last-child { margin-bottom: unset; } } } ``` When really, the world could be so much simpler: ``` .container { display: flex; flex-direction: column; gap: 1rem; } ``` No more margin hacks.

August 2, 2025

#30 Firebase as very peculiar limits, or: You don’t want to test in production 🙄

My “user admin” section for poketto.me is quite simple: it lists all registered users, shows when they first (and most recently) used the app, and lets me assign “entitlements” (features like the experimental podcasts and newsfeeds). Works perfectly well on my development instance — but in production, it kept crashing. Turns out: with Firebase, querying documents where a field value is `in` a list of values isn’t very smart — the list may only contain up to **30 (!) values**. ...

July 30, 2025

#28 Capacitor + Android Status Bar = 🤯

The Android status bar (that is, the small bar on top of the screen that shows the current time, the batter status, and notification icons) is really, really weird. It turns out, Capacitor will, by default, make your app a “fullscreen” app: It’ll render your MainActivity (the one that hosts the WebView which in turn hosts your web app) in such a way that the status bar isn’t there at all–on most devices. On some devices, however, the status bar will be visible, but transparently overlay your app 🤨And, to add insult to injury: It’ll change the font color of the status bar to white, so that if you rapp comes with a white background, all the user sees are some weird optical artifacts at the top of their screen. ...

July 28, 2025

#27 You don’t need to bring out the big guns right away (but it’s good to know them anyway)

It’s surprisingly hard to settle on a “fit-for-purpose” technology and tool stack for a modern SaaS / Cloud app. First of all, there are the technical decisions: 🔀 Which frontend, backend, and persistence stack do you use? Angular vs. React, Java vs. Python, Spring Boot vs. Rails vs. Django vs. Flask, MongoDB vs. Firebase vs. MySQL vs. Postgres… 🔀 Do you run it on AWS (Amazon), GCP (Google Cloud), or Azure (Microsoft)? ...

July 27, 2025

#22 GMail’s spam filter is pretty weird

I thought I was being clever when I implemented sign-in via email + one-time token for poketto.me: ✅ No passwords to store ✅ No reliance on external login providers like Google or Facebook And I had two reliable email services to send those tokens: Hetzner, via their all-inclusive web + mail hosting package I’m using for ralphmayr.com, and Zoho Mail, as a lightweight, email-only solution I’m using for poketto.me. On paper, everything looked fine: The SMTP server accepted the mail, and the message was sent. Simple, right? Wrong—especially when Gmail is on the receiving end. ...

July 22, 2025

#21 No, you don’t have to learn LangChain

...or LangGraph, or LlamaIndex, or RAG, or whatever new AI-hype framework is trending this week in order build an AI-powered app. More often than not, these frameworks are just wrappers around basic functionality—in this case, calling an API. And the layers of abstraction they introduce can make even simple things (“prompt an LLM”) feel unnecessarily complex. Take RAG, for example. All it really does is frontload your prompt with additional context. That’s it. In practice, it boils down to concatenating a few strings—something you can do in five lines of code. But LangChain adds layer upon layer of custom methods, config objects, routing logic, etc., that often just get in the way. ...

July 21, 2025

#19 Feedback is key 🔑

Back in my corporate days, I didn’t always give feedback the attention it deserves. But building poketto.me as a solo endeavour has reminded me just how crucial it really is. Working alone has its perks: you can move fast, make bold decisions, and follow your own vision. But it also comes with pitfalls: ➡️ You get blindsided by your own past choices ➡️ You can waste time iterating on suboptimal ideas ➡️ You miss what’s obvious to others ...

July 19, 2025

#18 Socket science isn’t rocket science! 🚀 Or: WebSockets + Flask + SocketIO = ❤️

For some reason, async communication between a web app backend and the browser causes more anxiety than it should (guilty 🙋). I’ve had my fair share of headaches with WebSocket frameworks before, but for poketto.me, I tried a much simpler stack—and was pleasantly surprised: ➡️http backend: Flask ( https://flask.palletsprojects.com/en/stable/) ➡️websocket backend: Flask-Socketio ( https://flask-socketio.readthedocs.io/en/latest/) ➡️websocket frontend: socketio-client ( https://www.npmjs.com/package/socket.io-client) 🔌 Backend: Handling connections is dead simple @socketio.on('connect') def handle_connect(): _, user_id = authenticate() sid = request.sid connected_clients[user_id] = sid 📤 Sending data to a connected client sid = connected_clients.get(user_id)\ if sid: socketio.emit('message', { 'message_type': 'save_changed', 'data': { 'id': save_id, 'state': 'archived' } }, to=sid) #### **🖥️ Frontend: Receiving messages is just as easy** const socket = io(environment.WS_BASE_URL, { ...

July 18, 2025