Last night I dreamt I was hit by a sandstorm. There were winds blowing so hard I had to cling to a groove in the wall not to be swept away. I tried running forward but everything was moving so fast around me. This is what development on Birch feels like.
I'm launching Beta v0.0!
It's still missing some important features (*cough* integrations, forms *cough*), but I think what's there is solid.
You can try it out now! birch.ink
Well, there aren't quite enough operations on tables right now. It's just .insert(), .last(), and .all().
No mutation, no indexing, no mapping, or filtering. That's all coming soon.
There's also no user-friendly way to get data into the system. You can hard-code functions yourself that insert the data you want, or you can POST /api/run to call a function with some data, but you can't easily have a non-technical user give you data. What we need are first-class forms... Coming Soon™!
And lastly, there's not much you can do with the data once it's in the system. I'm talking running functions on a timer. I'm talking integrations: First I'll add get and post primitives — sending http requests from Birch. Then an easy shortcut to email yourself. Maybe eventually... Airtable integrations? Google calendar? Salesforce...? Venmo!?
So you're telling me there isn't an easy way to get the data into Birch and once you get it in there isn't much to do with it?
Exactly! That's what makes me so excited – there's so much to build!
General Thoughts
Productionizing was harder than I anticipated. There were SSL issues with CloudFlare, bugs in Vite+Solid, and the usual annoyances of system administration.
As Birch is hosted on a single server, I can only store so much data that can fit, and I can only process as many function executions as that server can tolerate.
At some point I'd like to move my databases to CockroachDB instead of Sqlite. This will let me load balance requests over several Birch servers and support users who want to work with BIG data.
Birch would have to automatically set up Postgres logins for each user and then permission them to the right tables. Right now, I'm currently using bubblewrap to enforce data boundaries between users.
Why is running tasks asynchronously still hard with Ruby/Sinatra?? Seriously? It's not clear to me how to start a process in ruby (I'm using Open3) and then wait until it's done without blocking the main thread. It's not that it can't be done — I'm sure I could figure something out with EventMachine or by sending messages over the loopback network — but this is absolutely trivial in Go. (Or Elixir, or Javascript, kinda OCaml, maybe Python, maybe Rust)
My ruby server is only 875 lines; I might just rewrite it in a language built to handle async tasks.
It's nice to hit a problem that PL people love to talk about but never actually encounter while writing compilers 😆
I spent a couple days getting a billing system off the ground, but ended up shipping without one. Part of this work did make it in: a system for tracking how many function executions a user has left each month.
I think Birch is too volatile at the moment to recommend anyone use it to build serious apps. So for the time being, it only has a free tier.
I also set up a forum for people to post questions and comments about Birch. I'm hosting its server for $7 a month, and bought a MailPace subscription for $40 a year. I really like MailPace! Their whole thing is that they monitor the latency it takes to deliver an email and keep it fast. This makes them especially good for so-called "transactional" email like magic-links and whatnot. This is what the forum software I'm using (Discourse) does so I'm glad people won't have to wait that extra few seconds to sign up. (I've had speed problems in the past with MailGun and MailJet.)
I'm using NanoIDs instead of UUIDs throughout. They're UUIDs but with a bigger alphabet, so they look smaller in the url which I love :)