8 Hours to MVP?
by Christoph Bühler
My Wife and I had two beautiful months in Thailand. We did what is called “work & travel”. During that time, we made some new friends and learned a great deal about other cultures and countries.
The “KoHub”, a beautiful coworking space in Koh Lanta.
In Koh Lanta, we met James. He introduced us to “Killer Pool”, which is a round of pool with a – sometimes big – bunch of people. All contestants have a certain number of lives and if they do miss the shot or don’t pot any ball, they lose a life. On the other hand, if a participant pots the black ball, they gain a life.
Friday evening, Koh Lanta, “Free Decent”: Big Karaoke night. But some preferred beers (me) or playing Killer Pool (James). That evening, we played a round that had around 20 players. It was a mess. Lots of talking, lots of drinking, and no one paying attention to the game.
The Idea
The next Monday – after a hangover on Saturday – work was calling when James showed up and casually dropped the following sentence: “You know, some kind of app would be nice. People should get a notification if it’s their turn in Killer. Otherwise, you always wait”. That sparked a 🔥. It was around 8:30am.
The idea of fooling around with PWAs still stuck in my head. Alright, work had to wait. I dug into the topic and created an architecture. The goal was to create an MVP (minimal viable product) as fast as possible - we wanted to play pool that evening.
The API features, reduced to “create a game”, “join a game”, and “start a game”.
The game’s properties and “rules”.
A minimal user flow for the PWA.
9:00am: Scribbles were created and discussed. The idea set sail.
It was rather simple: create an API that is deployed on Google Cloud Run and a NextJS app deployed on Vercel as fast as possible. No tests, no linting, no best practices – just code as fast as possible.
Hi there, .NET my old friend! Create game. Get game. Start game. Join game. Leave game. Make a turn. API: done and done. Mashed in one API controller and directly accessing the database? Why not. It’s an MVP, you can always cleanup later - right? Time to have lunch? Absolutely!
The ugly duckling.
One Pad Thai later, the bigger task awaited me: Frontend. I fired up create-next-app and used the basic javascript template. No types, no testing, no linting, no nothing. It is quite exciting, after many years with backend languages, TypeScript, and all the likes, I threw all the best practices overboard and used React useEffect and useState everywhere. I just wanted to make it happen. Around 4pm, I had an application running. It looked absolutely awful, but it worked.
Next up was deployment. Vercel does an amazing job. Just hook up the repository and your app is deployed (more or less). The API required a little more attention: Hey Google, would you mind put the API on Cloud Run for me? - Of course, it wasn’t so easy, but two hours later it was cloud running.
There was some time left until we went out for dinner and tried the abomination that I created. So, I put in some effort and created some nice components with the help of Tailwind CSS. The result looked prettier than before, which was more than enough for me.
A little bit of Tailwind magic does the trick.
That evening, we had the chance to play Killer Pool with an installable PWA. With a true MVP approach! We could create games, start them, make turns - it was pure joy. Well, with one small exception: Notifications, the thing the started the journey. 😅
When I test my Killer Pool MVP, I do it in production.
Aftermath
A few days later, I rewrote the API in Rust with Rocket. It supports Server Sent Event streams out of the box, and I wanted to fiddle around with the Rocket framework. The basic functionality stayed the same, with the addition of server sent events instead of client polling (to check whose turn is up) and finally, notifications. The notifications only worked on the browser though. Apple devices did not have the necessary API (yet) and web-push has its own quirks in terms of delivering messages.
During the next week, we made some improvements and added small features. Of course, the code did not improve much, but in a real-world project, you could plan for these things.
Overall, it was fun and totally worth it to go all in and MVP the s*#t out of that idea. You can do a lot in 8 hours: From idea to a running App, with a database (Postgres) backed API. I had the chance to create something without thinking about guidelines, best practices, linting, testing, and all the things that are normally included in such projects.
And to my Wife, Theodore, Tor, Laura, and last but not least James, I say: thank you 😊 It was a great experiment and I had an amazing time creating and testing the MVP, it rocked! 🤘
Tools, Frameworks, and Links
What helped me create the MVP? What frameworks did I use? What other references are there?
- First of all, the repository (C# API): https://github.com/buehler/Killer-Pool-PWA/tree/v1.1.0/
- The next iteration of the API (Rust): https://github.com/buehler/Killer-Pool-PWA/tree/main/
- The App itself: https://killer-pool.vercel.app/
- https://vercel.com/ for deployment of NextJS apps without direct database access
- https://tailwindcss.com/ to make your web apps pretty
- https://rocket.rs/ to make your web API blazingly fast
- https://kohub.org/ for an amazing co-working space in Koh Lanta
- https://sgd.com.au/ is James’ Agency from Melbourne