Small Side Quest: Building a Simple Web App in Python
As a former iOS developer who’s now a senior manager, I’ve been feeling a bit trapped lately — not by the work itself, but by how little hands-on building I get to do anymore. I’ve always wanted to play more with web technologies, so few months ago decided to take a few hours and build something simple as an exercise.
The Idea
My goal was to create a simple web app that would allow me to go through the entire process—from coding to deployment—without getting stuck on the app's logic. I wanted something easy to build but that would let me explore all the related aspects.
So the idea is that the user selects a topic, receives a random set of questions from a question bank, and at the end, gets a score along with feedback explaining any incorrect answers and how to improve.
To keep things straightforward, I used static JSON files as question banks, with one file for each topic. When the app starts, it lists all available topics
Why Python
I know Python reasonably well, though it’s not something I use every day at work. Since I’m not really fluent in JavaScript, Python felt like the right balance between familiarity and learning opportunity.
But even then, I had to catch up on a lot of modern Python development practices; the last time I worked with Python, it was a mix of using pipenv, pyenv, venv, poetry, etc.—pretty terrible. So I checked again on how to set up a proper development environment in VS Code with launch.json, and just use uv along with linters like black, and ruff.
uv has its own quirks with options like --all-extras, uv sync --frozen, and unexpected behaviors with uv run but still it’s much much better than it was before uv.
It's surprising how long it took for the industry to develop good tools for one of the most widely used languages in the world, but now, in my opinion, it's very usable and reasonably straight forward.
Working with data
Loading JSON files became a little side project where I learned Pydantic, and once I understood it, it made validation and data handling very easy.
UI with NiceGUI
For the frontend, I chose NiceGUI — someone at work mentioned it to me after I’d had some frustrating experiences with Streamlit in the past. I remember that in Streamlit, some simple things (like controlling one dropdown based on another) could get unnecessarily complicated.
NiceGUI worked surprisingly well for my case. It let me build a clean, interactive UI directly in Python without touching JavaScript.
Because of it, I also ended up learning a bit about Tailwind CSS. At first, I found the concept counterintuitive, but once I read more about what problem it solves — especially in larger teams where consistency matters — I was really impressed by its design.
A Bit About Docker
Writing the Dockerfile was another mini-adventure. I had some shallow understanding from before, but this time I dove deeper — learning about how layers work, and how to make builds faster and cleaner. It was a good reminder of how much thought goes into the tools we now take for granted. The uv website has a good explanation on how to build Docker images with it.
Wrapping Up
The whole thing was small, but it was exactly what I wanted — just two evening sessions of hands-on building that gave me a full end-to-end experience. I already knew most of the concepts but wanted to explore them more deeply, so I deliberately kept my use of ChatGPT contained. For most of the topics, I used it only to learn, and for everything else (like Makefile, README, helper scripts, etc.) I used it in a more extensive way. It made the project feel like genuine, focused practice rather than automation just to get it to work.
The result is on github.