This page rates technologies I've used to build [ReadIt](https://readit.bot) on the following scale: βœ… **Adopt**: I've used this successfully and recommend it. πŸ˜• **Meh**: I use this, but it has rough edges and I'm exploring alternatives. πŸ›‘ **Avoid**: I've used this in the past and *do not* recommend you adopt it. # Databases ## Prisma πŸ›‘ **Avoid** https://www.prisma.io Prisma is an ORM for node. It includes a DSL for describing a database model, and tools for generating clients and performing migrations. Reasons to avoid: - Latency: Moving from Prisma to plain SQL reduced the latency of my API endpoint by *over a second*. Some of this is client latency, and some of this might be faster AWS lambda startup due to a smaller package size. - ![[Pasted image 20240528105728.png|500]] - Migrations: Migrations are terrifying. If the schema does not match the DB (ie, there has been DB drift) the default recommendation is to *reset the database.* This is almost never the correct solution, but it's the first thing Prisma recommends. Even worse, the docs on how to non-destructively fix DB drift do not work. - Complexity: ORMs introduce unnecessary complexity. Rather than spending time learning Prisma's API, just learn SQL. Migrations don't have to be complicated. They can just be a folder of `.sql` files and a simple tool like [[#Flyway]]. ## Vercel Postgres πŸ›‘ **Avoid** https://vercel.com/storage/postgres Vercel Postgres is Vercel's Postgres-compatible serverless database technology. It's serverless in the sense that when the database is idle, it is suspended, and you only pay for the compute time that you use. The marketing material says it scales up seamlessly. Reasons to avoid: - Latency: When the DB starts from a suspended state, I see latencies of over 1 second for simple queries. - Reliability: Timeouts and weird DB connection drops are the number one reason for 500s on my small project. - Cost: My small project generates way less than 1 RPS and I still easily exceeds the compute included in my Vercel "Pro" plan. - It's a trap: It doesn't support replication, so good luck ever migrating off of it. - Extensions: It doesn't support Postgres extensions. - `psql`: When I connect with `psql`, it constantly locks up. I suspect this is due to the DB suspending itself when idle. - Bugs: It's just an immature product. The sad little query editor in the Vercel dashboard is buggy as hell. ## Yesql βœ… **Adopt** https://www.npmjs.com/package/yesql This is a node library that provides an API for loading SQL queries from `.sql` files: `queries.sql`: ```sql -- updatePokemon UPDATE pokemon SET price = :price; -- PostgreSQL / MySQL named parameter style ``` Then in your program: ```js const sql = require('yesql')('queries.sql', {type: 'pg'}) const named = require('yesql').pg const pg = require('pg').connect... // read from file pg.query(sql.updatePokemon({price: 5}), (err, result) => {...}) ``` If you're SQL-pilled like me, this is a great way to manage SQL. You can enabled SQL syntax highlighting in these files and run SQL formatters. This is way better than writing SQL in javascript strings. ## pg βœ… **Adopt** https://www.npmjs.com/package/pg pg is a library for querying Postgres databases. It has a pure node implementation and also native bindings. So far I've only used the pure node implementation. In conjunction with [[#Yesql]], the has just worked, which is really all I ask for when it comes to a DB library. Get out of my way and let me write SQL! ## pg-mem πŸ›‘ **Avoid** https://github.com/oguimbal/pg-mem pg-mem is an in-memory implementation of Postgres. I got really excited about using this as a lightweight way of testing my DB queries in unit tests. Unfortunately, it starts to fall apart with even moderately complex queries because it doesn't support most built-in functions like `EXISTS`. It provides an API for implementing functions yourself, but I could not get it to work. ## Flyway βœ… **Adopt** https://flywaydb.org Flyway is a tool for running database migrations. Like many migration tools, it uses a table to track which migrations have already been applied. Migrations don't have to be complicated! One of my key criticisms of tools like [[#Prisma]] is that they over complicate things that should be simple. A migration is just a set of SQL commands. Just let me store these in `.sql` files and give me a tool for executing them in order! That's basically what Flyway does. It doesn't even have a javascript API, but that's ok because I don't need a javascript API. To run the migrations in my unit tests, I just explicitly run them: ```js beforeAll(async () => { client = new Pool({ connectionString: "postgres://user:postgres@localhost:5432/unit_test_db" }) await client.query(`DROP SCHEMA public CASCADE`) await client.query(`CREATE SCHEMA public`); // Run the migrations! await runMigrations('db/migrations/B1__init.sql') await runMigrations('db/migrations/V2__add_voice_selection.sql') await runMigrations('db/migrations/V3__add_total_bytes_to_episode.sql') await runMigrations('db/migrations/V4__add_balance_activity.sql') } ``` `runMigrations` is just a simple function that reads the file and queries the DB. None of this has to be complicated! Why do we keep adding layers of abstraction to things that are simple???? # Hosting ## Vercel πŸ˜• **Meh** https://vercel.com Vercel is hosting platform that specializes in hosting Next.js applications, a framework which they maintain. Deploying is as simple as pushing the Next.js project to a Github repo. Vercel then builds and deploys the application. It uses a serverless architecture, so you only pay for the compute required to deliver your webpages. Vercel very successfully delivers on the promise of simple deployments. It really is as easy as pushing to a Github repo. Where it falls apart is: - Serverless Latency: This is a problem I run into again and again with serverless. I'm not sure exactly how Vercel works, but if it's similar to AWS Lambda, it works by loading your code into a container that is booted when your site receives a request. The overhead of starting the container is the primary source of latency. I find this intolerable because simple pages shouldn't take over a second to *start* loading! - Operations: Vercel's operations story isn't very good. What I mean by operations is all the stuff you have to do to make sure your site is running reliably. Want to review logs? Well I hope you're checking frequently because **maximum log retention is 24 hours.** Want to alert on 500s? Sorry, you'll have to manually call the PagerDuty API from inside your Next.js app. Third party integrations offer solutions to these issues, but do you really want to go further down the rabbit hole and be forever dependent on Vercel? ## AWS βœ… **Adopt** With the [Free Tier](https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all), you probably won't pay anything the first year, and if you do, the prices are very reasonable. Yes it can be complicated, but time spent learning to use AWS is time well spent. # Payments ## Stripe βœ… **Adopt** https://stripe.com It works and the docs are great. My only complaint is that there's no way to be notified of failed webhooks, which is how your site is notified of payments. # Frameworks ## Serverless βœ… **Adopt** https://www.serverless.com This is a framework for writing serverless APIs, primarily in AWS, but other cloud providers are also supported. I've had a good experience with this framework, and it simplifies a lot of AWS's APIs. If you just want some AWS Lambda functions connected together with queues (the Simple Queue Service), this does the job. Describe what you want in the `serverless.yaml` file and implement the functions in Typescript or Python. Serverless will handle deploying it all to AWS with a single command. It's free and open source. You don't have to sign up for their premium dashboard thing to use it. But wait didn't I say serverless sucks in my section on [[#Vercel]]? It does suck if the thing you're writing is a website. Don't subject your users to that latency. That said, there are many other things you can implement with serverless where latency is less of a concern, like a [text-to-speech pipeline](https://readit.bot). # Developer Tooling ## Supermaven πŸ›‘ **Avoid** https://supermaven.com Supermaven is an AI coding assistant. Its primary selling point is that it's fast and has a large context window. Unfortunately, I just didn't find it that useful. The completions were often not relevant or worse: buggy. One particularly egregious example is that it kept telling me to write this: ```js promises.forEach(async (v) => {...}) ``` This is a common footgun. This will sometimes appear to work, but will other times subtly break. The issue is that `forEach` doesn't actually await the async lambda. In a serverless context, your node process might completely exit before all the promises complete. Anyway, code like this was making it more of a liability than it was worth. That said, these types of tools are improving all the time. Maybe check back in 6 months? # Languages ## Typescript βœ… **Adopt** As mentioned in the section on [[#Serverless]], I've been implementing my AWS Lambdas in Typescript and it has been great. The type system is actually fantastic and has saved me from a lot of bugs. It manages to make some extremely advanced type system concepts easy to use. So easy that you might not even realize that you're using [dependent types](https://www.hacklewayne.com/dependent-types-in-typescript-seriously). It has inherited a few rough edges from Javascript, but overall I enjoy coding in it. # Other Stuff These are things I'm using, but don't really have a strong opinion on. This is mostly front end stuff. I don't have much experience writing front end code, so I don't think my opinion here is terribly valuable. That said, these are all tolerable enough that I continue to use them: - Next.js: A web framework. - Tailwind: A thing for CSS, or rather a thing that makes it so you don't have to write CSS? - Lucide: Some nice icons. - Radix: UI components