←back to thread

873 points belter | 2 comments | | HN request time: 0.001s | source
1. z33k ◴[] No.42964352[source]
How come a fully typed ORM is the devil, if we agree we want a typesafe codebase for our mixed experience dev team? I have had positive experiences with Prisma. It just works.
replies(1): >>42965509 #
2. zamalek ◴[] No.42965509[source]
I personally draw a distinction between micro-ORMs and ORMs. A micro-orm will simply take a strongly typed flat struct and map it into the set of parameters for a query, and likewise map a single row out to another flat struct (or enumerate/iterate while doing so). They may even include insert, update, and delete helpers that deal with a single table. This is what 90% of Prisma does and is the Good Parts. Migration generation is also good (but can be dangerous, e.g. deleting columns).

I'll call out query generation separately, as it is a lesser evil (in my opinion). This falls under a larger peeve of mine, which is using data (JSON, YAML, or this[1]) as programming languages. Using data as a programming language sucks. Tooling (compilers, LSP, etc.) are typically absent, meaning that mistakes very much become a runtime issue (not really a problem for Prisma). The deeper problem is that you'll run into limitations and will: either have to drop down to SQL (tricky given that you've rarely used it thanks to using ORMs to generate all your queries), or kludge/hack it up in order to remain in the ORM land. There's also lines of code and readability to contend with, the second Prisma example (the first is on my shit list for reasons further down):

    const result = await prisma.user.findMany({
      where: {
        OR: [
          {
            email: {
              endsWith: 'prisma.io',
            },
          },
          { email: { endsWith: 'gmail.com' } },
        ],
        NOT: {
          email: {
            endsWith: 'hotmail.com',
          },
        },
      },
      select: {
        email: true,
      },
    })
vs.

    SELECT u.email FROM users u
        WHERE (u.email LIKE '%prisma.io' OR u.email LIKE '%gmail.com')
          AND u.email NOT LIKE '%hotmail.com'
Just write the fucking SQL.

The objectively bad parts are one or more of the following:

* Change tracking: magically being able to update a value returned by the ORM and calling `save` to write it back to the DB.

* Object graphs: magically accessing related objects in memory, e.g. `order.orderlines` or `order.address.city.state`.

Relational databases (SQL) are not graph databases (in-memory object hierarchies). They are orthogonal concepts. Just throwing whatever you have as your classes into your database is neglecting to think about how your data is stored. This will come back to haunt you. You might claim that you can do the careful design using classes, and I would believe you, however, those juniors you mentioned aren't going to have the knowhow (because they've been shielded from SQL by ORMs their entire career and so don't understand how to make good databases).

Case in-point, back to that Prisma example shown earlier. Any ideas what's actually wrong with that query, besides the pointless hotmail check? Both the original and my conversion have the same serious issue that stems from not designing the database.

[1]: https://www.prisma.io/docs/orm/prisma-client/queries/filteri...