richiejp logo

On creating a booking app with SvelteKit

Intro

For the most part over the last 5 or 6 years I have been employed to work on the Linux kernel. Finding, reproducing and fixing bugs. Also on test automation and things I am unmotivated to write about. To get a feel for the kind of stuff I usually work on, here are some articles I have written related to my job:

I also wrote a data analysis framework in Julia which failed horribly. The major issue being no one I wanted to use it, would use it. I made it do the job I needed it to do. However the engineers I wanted to use and expand it wouldn’t do so.

Other people were interested in what it could do if I (or someone else) made it do it. Indeed it turned out that Palantir had made a very successful business out of a similar concept.

This helped in my conclusions of what not to do when creating a project. The semi-serious linked article can be summarised as follows; you can encourage failure by doing the following things:

As you shall see I am not terribly good at following my own advice. However I perhaps have managed to avoid the worst excesses.

UPDATE

Since writing this the app is now live.

At the time of writing I’m putting the app into maintenance mode while I find other ways to make my life more difficult. I have written more about it on IndieHackers.

Indie Hacking

I want to create my own products and be exposed to the risk of running my own business. Meanwhile I don’t want to completely run out of Beer tokens and be forced to drink lighter fluid like Withnail.

It would be more respectable for me to use my family as the reason why I can’t just quit my job and go full entrepreneur. However that wouldn’t explain why I didn’t do it before I had a family. So really it’s just left to your imagination (or you can buy my book when I finish and publish it).

Anyway my employer were good enough to allow me to go part time and work on my own product or freelance. My backup plan was to quit and freelance initially. This is almost what happened, but handing my notice in seemed to push things along.

Initially it looked like they had a serious problem with me going part-time, but this wasn’t the case at all. Someone just needed to do the work to change my contract and IP agreement. Don’t get me wrong, nobody liked me going part-time, but it was deemed better than me disappearing altogether.

Being on 50% salary and splitting my week in half is less than ideal. I find it far better to work on things serially in solid blocks of at least a week.

Meanwhile the salary will stop us from going bankrupt, however it’s “not enough”. I could elaborate further, but I think it suffices to say that sooner or later we will be uncomfortable.

Nevertheless this is good enough; I should be able to do something with it. A lot of ink has been spilled on whether people should try a side project or go full time immediately. Obviously it depends on your circumstances, including what opportunities are in front of you.

Update!

Splitting your time 50/50 is fine. It’s important to move fast, but there is a hard ceiling to the work hours in a week anyway. There are far more important things than maximising focus time.

To be clear a few hour chunks of focus time is essential to get anything done. After that though, what one chooses to do is far more important.

The major problem was (and perhaps still is) finding a problem which I can identify a sensible solution for.

Update!

Or sales, but if you have a great product then it only needs to be put in front of people. Still, I would seek to get buy-in from more than one person before writing a line of code for a future product.

I explored a few opportunities, some of which are on hold, but settled on a booking app in collaboration with my sister, a professional musician. This is more than feasible to complete as a self funded part-time project.

It’s incredible to think that in 2022 this isn’t a solved problem. However she wasn’t completely happy with any of the available solutions.

She has an existing system comprised of disperate components which allows her to automate some aspects of her business. The idea is to create a streamlined and tightly integrated app from the system.

Firstly so that it can be resold to similar businesses or individules. Secondly to allow some types of automation which requires complicated logic. Thirdly to make the booking process highly polished.

To be clear my sister is more technical than many other people with similar businesses. Not to mention the amount of time she has spent over the years on her website and admin process. Other people are not as likely to cobble together their own automation out of various nocode tools.

Because my sister’s system is quite complicated, not to mention the things she hasn’t been able to implement herself yet. I asked her to provide an idea for a minimum viable product (MVP). Which turned out to be an availability calendar and simple enquiry form.

These things exist already of course, they just don’t fit the usecase. They don’t look right and are usually too complicated and expensive. Meanwhile it’s clear there are performers out there who could make use of such a product if it were simple to use.

Presently they will be taking enquiries for days where they are already booked or unavailable for some other reason. My sister also pointed out that her availability is a marketing tool. Her unavailable days are evidence she is in demand.

Whether or not people are willing to part with money for these reasons is another matter. The proliferation of similar software would suggest that people are willing to pay for this. Perhaps this won’t include the people in this tiny niche, we shall see.

I decided to make this a subscription based web application for the obvious reasons. My target audience aren’t going to want ot install the software themselves on a web server or meddle with the source code. Furthermore this doesn’t preclude me from making it “shared” or open source at a later date.

You may also wonder if working with family is wise. I think that depends on your family and what it is you are doing. For the time being my sister is under no obligation to use or promote the app and I’m not under any obligation to provide it. At least beyond the basic principal that I said I would try, so I will at least take it to the point that it’s clear it won’t work.

If it does work to any extent, then things get more complicated. We still need to decide what amount of profit the app needs to make for each of us to keep us motivated. The amount of motivation for each of us depends on the division of responsibilities and intellectual property being exposed.

Leaving this kind of thing to be sorted out later requires a lot of trust. We somehow need to negotiate this without making Christmas dinner very awkward. The risk of a serious fallout is very low in my opinion, but it wouldn’t be good if it did happen.

Techfoolery

For someone who has hitherto avoided front-end development like the plague; this may not be considered the wisest choice. Indeed keeping myself focused on features visible to the end user has been a nightmare.

At one point I began writing my own database so that I could run the app on Nanos unikernel VMs and avoid making NodeJS (de)serialise RESP (Redis’s communication format). Without writing native modules, NodeJS/V8 is pretty bad at reading any format other than JSON because JSON.parse is implemented in highly optimised native code by the V8 team.

Update: I’m probably wrong about the performance. It seems V8 can deliver near native performance. The problem is the JavaScript ecosystem.

So really it makes sense to have a database that just sends and receives NodeJS optimised JSON over a web socket (or whatever). At least that is what I think. I haven’t implemented it because it is not even remotely necessary for my booking app (although I think it would be similar to Firestore, see below).

Update: Or MongoDB and indeed PouchDB discussed below.

On the plus side, I see a non-stop list of ways in which web app development can be improved. Forcing myself to write a web app has exposed me to the real challenges of modern web app development.

There is clearly a lot that can be done at every stage in the stack. There are no shortage of ideas, the issue is finding one that I can monetise in a reasonable time frame.

I have previously done web dev in a bunch of frameworks. None of which I was terribly familiar with, so I went looking for what start ups and indie hackers use today. I guessed this is the the group I want to copy because people who make the wrong choices are filtered from the group.

It appeared that the most popular seems to be Next.js on Vercel with Firestore as the DB. Next up SvelteKit also on Vercel and PostgreSQL on Supabase or whatever.

I decided that Svelte(Kit) was too new and tried Next.js first. However I hated it, or at least I hated React. It’s a bloated verbose awful thing with docs floating around for legacy API features. It seemed like a lot of work to do something very simple in React.

So I tried SvelteKit also on Vercel. Initially with Bulma CSS which I have used before, but got annoyed with it and switched to TailwindCSS which seems to be more popular. I’m still using SvelteKit and TailwindCSS which says a lot about those two things.

Svelte creates really svelte client side JS and the Svelte syntax is also nice and concise. This contrasts heavily with other client JS libraries which transfer a lot of JS and get into all kinds of complications to make pages load quickly.

The ‘Kit’ part of SvelteKit is not quite as brilliant. It’s not V1 yet which is my own fault for using it before V1. However I wonder if even when it is V1 I will still have a mild itch to replace it.

Update!

I got “hosed”, by SvelteKit and ended up replacing the Kit part. They totally change routing and I never figured out how to get error reporting how I wanted it.

Meanwhile the Svelte part has been steady as a rock. I replaced Vite with an ESBuild script, wrote my own client side router and used Polkadot on the server.

Everything was going pretty well with Vercel until I started looking into databases. In fact it is better to say everything was going pretty well until I looked into databases. This threw all my hosting plans into disarray.

It’s worth mentioning that at this point. Despite some chopping and changing with front end frameworks. I had quickly created a mock UI that my sister was happy with. Which is quite similar to what’s there now.

Things got rapidly bogged down though. Perhaps due to my personality, but I also suspect there is something missing in the Vercel or serverless calculus.

Regardless of what database you use it’s not going to be in the same VLAN as Vercel’s server (or whatever they would like to call it, considering they are serverless). Possibly it may be in the same datacenter depending on who you use to host your database.

This serverly reduces the number of options you have for databases. You need a secure DB exposed to the internet and that can accept many simultaneous connections (because “serverless”). Regardless of what you pick there will be some latency added.

Firestore, amongst others, can handle this and I suppose you can host your app on Firebase as well. I imagine that latency is not too much of an issue then. However you can’t very well pick up an app designed for Firestore and Firebase then move it to a different host.

Firestore in particular is owned by Google who’s calendar and auth API’s I do use. However I don’t want a significant portion of my tech stack to be reliant on one vendor. I’m not just thinking about my current project, but future ones as well.

Also the pricing is based on a variety of metrics including some relatively high level ones. Like the number of document writes and reads. Also the stored data and network egress. This doesn’t leave many degrees of freedom with which one has to optimise.

When pricing is based on VM resources you have many degrees of freedom to optimise. You can send more or less requests based on what actually results in lower memory, storage and processor usage.

In other words, by using these hosted databases you are giving up a lot of optionality. Admittedly this won’t matter for most developers, most of the time. Perhaps I could have saved a lot of time by using Firestore.

Without having decided on my hosting, I decided to try using PostgreSQL for my database. It is very popular and there are lots of options for hosting it that also support a NodeJS instance.

I tried using it with a ORM that is not an ORM, but it just seemed to get in the way of using PostgreSQL features. So then I tried writing raw SQL/DDL where (as usual) I was greeted with weird compilation errors and a manual full of ad-hoc features no one outside of enterprise uses.

Previously I have simply resorted to using Redis and implementing the indexes myself if really necessary. I thought I would be sensible this time and not do that. However here I am again, using Redis.

However this is where things start to get crazy. I got fixated on using an embedded database, like LevelDB, BadgerDB or PouchDB. This would then allow me to host the whole app in a single VM on Vultr running nanos.

Update: I severely regret not trying PouchDB in NodeJS and a central CouchDB instance for operations which must be consistent.

In the meantime I was making some progress with app features using Redis. Including some Lua libraries, a feature introduced in Redis 7.0, that I later was forced to remove due to the awful nature of Lua. This is despite having made hosting decisions based on needing Redis 7.0 that almost nobody supported.

The Redis Lua problems made me question Redis altogether, again. However I was also thinking that actually an embedded DB is not such a great idea because how would it scale? PouchDB can probably do that, but it’s performance is maybe not so great to begin with.

Then I would think well I should just use Redis, I know that works already. I just need to throw out the Lua; I can make do without it.

However Redis forks to write to disk, so it doesn’t work with nanos. So then I have to host it elsewhere. Maybe in a container, but I hate containers. Reading the Kubernetes documentation almost gave me a hernia.

I started writing a JSON document database in Go (I’ve never used Go before) based on BadgerDB. With the intention of creating something that my NodeJS VMs could offload data operations into.

By this point I think I had fully lost the plot. The whole point of using Redis was that it is just a default option. I’ve used it before, it’s simple, well supported etc. It’s probably not ideal, but this project isn’t for exploring databases.

At any rate, I discovered Fly.io and got over my hatred of containers for now. I think Fly gives me enough freedom while taking away most concerns about updating the Linux kernel and various packages. I especially do not want to maintain Kubernetes.

Update!

Oh, but it doesn’t end there. I got into trouble with Redis because Fly.io shutdown the instance because the physical host storage was full. Then I tried Upstash, which I didn’t like. Eventually I switched to KeyDB with active-active replication which is HA and eventually consistent across regions.

It’s still far from perfect. Again; should have tried Couch/PouchDB.

So eventually my tech stack is comprised of a NodeJS 18.x container with the following deps SvelteKit (Vite), Vitest, TailwindCSS, TypeScript, ioredis. Then another container running Redis 7.x.

My app talks to Google’s REST APIs, it also sends mail through Fastmail using JMAP and logs to Loki. Amongst other things, I implemented these from scratch instead of using libraries.

I haven’t regretted these decisions, it makes the server side code small and maintainable. I’m only left to deal with breaking changes from SvelteKit and Vite updates.

As everyone says, even quite basic NPM libraries themselves use many dependencies. They are also full of shims and bloat that isn’t completely solved with “tree shaking”. Not least because I still have to download it all on my dev machines.

There are a lot of things which really bug me, but all in all my Svelte app is very svelte and I feel like I now have a tailwind allowing me to progress très vite.

Updated contemplation

Eventually I ended up writing a whole lot from scratch. I don’t regret this when it comes to the core of the application. That is the calendar itself. What I do regret is putting this level of effort into things merely supporting the core component.

Reducing ones dependencies to those with a very high value-to-maintenance ratio means I have good performance, security and low maintenance. More importantly to the customer, I have microscopic control over the product behaviour where it matters.

The problem is obviously that it’s a big effort to write everything just the way you want it. Meanwhile the payoff for having microscopic control over the menu and landing page (for e.g.) is small.

I believe writing from scratch is a huge edge. However it’s an edge because it is hard. You can easily blow a month reinventing the wheel then ending up with a substandard solution.

On the other hand, you can get a vastly better solution, that is faster, more secure and lower maintenance. Without doing anything fancy, just removing complexity your application doesn’t need.

As usual I believe the solution here is not compromise, but a bar-bell strategy: write the core from scratch and use no/low code for the periphery.

If I were to start again I would either use BudiBase or Google Apps Script/JSON for the user panel. The later is necessary to get a Google Workplace plugin anyway.

Likewise I’d use some kind of no/low code platform for things like the landing page and docs. I think this will produce an average solution without much effort. Which is all that is needed to let the core shine.

I think it is essential that the no/low code platform is fully managed. It’s possible to self host BudiBase, but I do not trust apps that complex unless they can be given constant attention.