Patatoa

My Spurs Game

My latest project started with the thought, “isn’t it funny that Eddy Curry was on the Spurs?” That obviously spiraled to other “‘member him?”s and other players who maybe should have been Spurs and voila. Make a quiz about it. I wanted to try something new and as the idea percolated, htmx had its moment and that was going to be the tip of the iceberg for this project. I learned that htmx was really just a fancy new JavaScript library, with the twist that it expects HTML from the server. Now I needed a server. I have been looking for a reason to learn Rust, and all the cool kids are pairing Go with their htmx, but I didn’t know what I was getting into with htmx yet and wanted to stay a little safe and use TypeScript on the server. I still wanted to be saucy, so I chose Deno as my runtime instead of Node.

Unrelated.

Deno has some mature-ish web frameworks, but it has a HTTP server built in and I wanted to stay low level. Deno has a cool html templating library, so I used that and essentially recreated TSX (I could have probably just used TSX some who’s but this worked just as well, so why bother?) I made some simple routing for my different controllers. The /api route corresponds to the playerController which homes all the game logic. There is a session controller used at the beginning of the game to check if you have game to resume or not. I route any requests with a file extension to a static file handler which I implemented. Any other request serves the index.html — the “single page” of the application, essentially.

I opted to use PureCSS as my style system. The grid system it has is pretty cool and saved me a lot of layout work, but any other component it offered I either didn’t need to specifically chose not to use. I might just use Tailwind next time. As the project developed, htmx turned into a terribly tiny part of the project despite being the primary technical decision. I used it in only two ways. On the initial load, I use the hex-trigger=“load” trigger on an element to call the session controller and return either the “Welcome” message or the “Welcome back!” Message. After that I use it to hx-post the main game form. Perhaps there are fancier things available but, why shoe horn complexity and, in this case, I think it shows the utility of htmx. I didn’t need to script a function or Ajax call in anyway and didn’t need to worry about how to scaffold the return. At first, building the html on the server set off my “separation of concerns” alarm. But then I said, fuck the concerns. The web was intended to have servers serve html to clients and it was less headache, and more straightforward making the html template. No need to worry about what was going to be server side or client side, no need to make another ViewModel necessarily (though I did since it was nicer). Htmx was a win. Would recommend and use again.

Deno is mostly great. I don’t have any real gripes. My experience with Node as a platform with a standard library was minimal since so many other developers had built better, easier to use tools on top of Node I’d use those. It felt great to use so many tools built in and in the official documentation. It seemed fast enough to me, not that I was taxing it or needed incredible performance anyway. The wrench came with deployment.

I hadn’t decided on where I would host. I read a persuasive article against Google Cloud Platform, where I hosted other projects of mine. While I can’t say experiences with GCP are bad, its also the only platform I use in me free time. I wanted to branch out and AWS had plenty of tires to kick. Two whole weekends were spent gathering player images, editing the images, storing the images in s3, then writing blurbs for each player. I needed to store the user’s game data (which players they saw, and whether hey got the question right or not). I wanted to use a Redis-like solution and wanted to use a AWS native offering, but ElastiCache seemed a little too expensive for what I needed. I defaulted to DynamoDB, which is the Document DB offering. It’s fine, the price is right, and realistically, as fast as I need.

I built the app with docker which I figured wold help when it came to deploy, since Deno isn’t going to be a supported platform wherever I go. I expected to do something like Cloud Run. I got cold feet on using AWS Fargate (probably unfounded) so I chose Lambda. This turned to be a bit of a set back since now I had to rewrite my server. Whether or not I had to, I certainly didn’t know better so I took out the native Deno server code and replaced it with a Deno lambda library. It is native Deno so I didn’t feel Ike I was totally cheating, and the API was different enough that I felt I needed to migrate. It wasn’t painful or too different from what I originally had and sped up time getting it running in AWS. After futzing with DNS for an afternoon, the site was essentially live!

Informative?

I’m a strong proponent of leaving your dough a little lumpy, but I had a few things bothering me. Loading was fast, but I felt it could be faster. Cold boots aside, there were three main phases to my load, each taking half a second: serving index.html, serving my custom css, checking the session for the welcome message. And sometimes on my phone, it wouldn’t finish making that first async session call which bothered me. The CSS was issue 1. I could have shoved it in s3 and call it a day, since the css was going through my static file handler and the calls to fetch the player images were pretty speedy. I took a page from my Next JS projects which inline the css, and I thought to do that — add it to the index.html so it ships together, eliminating a fetch entirely. My solution here was to add a build step to my dockerfile. I created a bundler.ts file that reads my css file, minifies it, and adds it to the <head> of my index.html. This way developer side I keep my separated css file, and server side its all already bundled together with no extra cycles spent on it server or client side. Sweet! There may be a Deno bundler or maybe could have used whatever the kids are using these days, but this suited me fine. Smart in the smart ways, and smart in the dumb ways.

I was down to two loads (and one possible bug), and I was kind of fine with that. To pretty it up I spent some time leveraging another htmx feature and implemented a loading indicator. I got it working, and then explained it to Henry, my son, and he told me what I needed. “Why don’t you just do that at the beginning?” Which I knew was the right answer a week before when I first scaffolded the htmx and server. But I didn’t want to do it that way because I really wanted to use that htmx hx-trigger=load. There was no reason I couldn’t know on the first request whether the player had a previous session or not. I should just pre-populate that from the get-go. I just needed to hear it from Henry The loading indicator was a sunk cost, I renamed the session controller to a session “handler” since I no longer needed the session controller/route. When I in-lined the css, I removed the static file handler entirely, so my server only needed to handle the game logic or the default page serve. Sweet. I removed one of the only two ways I was using htmx, but that is still the core of the user interaction. That, be speedy, and don’t confuse me with an error. But like with writing, the best sessions are where you remove your work.

While I developed this, Bun had its moment, so I second guessed my choice of Deno. But, Deno was fine and its integration with VS Code is great. I’ll definitely need to find a way to use Bun in the future, but Deno was great to use. Don’t see why I’d choose to use Node over it at this point. Htmx was great, which I’ve said enough. My AWS experience was pretty good too. I think my DynamoDB-Lambda stack was the right call. In my times of trouble, I thought about spinning up an EC2 instance, and running on there, but I stayed brave. Persevered. Stayed serverless. Stayed based. Even with a significant rewrite for lambda, and DNS futzing, most of the work was spent on the content of the game. In the year 2023, that’s how it should be.

I hope all that doesn’t show. I hope you visit and find a somewhat amusing Spurs quiz that’s just enough of a diversion to share.