1. 41
  1. 11

    Feels unusual reading something from Dan Luu that also has CSS.

    1. 2

      Do you think he has a gun to his head?

    2. 4

      using SQLAlchemy (which makes it hard for developers to understand what database queries their code is going to emit, leading to various situations that are hard to debug and involve unnecessary operational pain, especially related to the above point about database transaction boundaries)

      I’m also a fan of raw SQL. If I would be asked for mistakes I have made, I would as well name the database abstraction (in my case peewee). Two things that annoy me: The database is now mixed into my models and peewee has a very global connection management. I would much rather like the model to be totally independent from the database layer and do explicit connection management. E.g.

      # no active record, no implicit connection tied to the model
      my_object = Customer(name='John Doe')
      # CustomerDbLayer must contain all the logic to understand
      # how to store a Customer into the DB
      # (as well as how to read one from the DB)
      cdb = CustomerDbLayer(db_connection)
      cdb.save(my_object)
      

      It’s a bit surprising that at the end of the article they mention GraphQL and Kubernetes as some of their good decisions, two technologies which I would definitely not list in the section boring. At least a few years ago both seemed quite the hype to me.

      1. 4

        Kubernetes reminds me a lot of way back in the day when I was first learning about sendmail and was like “wait, this thing’s config is so complex people have to use and configure another tool just to generate the config file for it?” Except with Kubernetes it’s often multiple layers of that going on.

        The specific case with SQLAlchemy there is one that I’ve seen be a problem at a previous employer (where control of exactly when, what, and in what order queries ran was important for regulatory compliance), but is more an issue with the session/unit-of-work/magic-optimization approach than with ORM or DB libraries in general. Plenty of ORMs and DB libraries give you much more fine-grained control of when queries run, when things get flushed to DB, etc.

        1. 2

          I’ve found out about https://github.com/nackjicholson/aiosql last week and it hits is the perfect balance imho. I knew about a similar lib in clojure from few years back ( https://github.com/krisajenkins/yesql) but I hadn’t found anything equivalent for python.

          1. 2

            Have you seen PugSQL?

          2. 1

            GraphQL is just an old school RPC protocol. How is it not boring?

            1. 4

              GraphQL doesn’t have a well-defined story for caching or error handling, both of which are otherwise boring HTTP built-ins.

          3. 4

            How Wave uses SQLAlchemy exactly is not mentioned in the article, but what is described (global session) is certainly not SQLAlchemy’s fault.

            SQLAlchemy makes it easy to shuttle database elements in and out of Python objects. Is it absolutely necessary? Of course not. Is the alternative simpler? Well, it depends on how you look at it. Shuttling data in and out of Python objects can be PITA.

            SQLAlchemy has two interfaces, core and ORM. Although not explicitly mentioned, I imagine the author is refering to the ORM interface, which does abstract away the raw sql but it is quite intutive. There is also a way to run raw sql queries if you like so using python code to string together sql queries is not the only option.

            Btw it is certainly possible to manage your connection lifecycle anyway you like with SQLAlchemy. Global request session is not unavoidable.

            The actual issue behind the visible issue in the article might be that it takes a certain level of experience with SQLAlchemy (or any library, tool, language for that matter) to use it appropriately and productively. It’s easier to find devs with less experience than more, so keeping the design simple also makes it easier to resource the engineering department with cheaper, more general purpose devs.

            1. 2

              How Wave uses SQLAlchemy exactly is not mentioned in the article, but what is described (global session) is certainly not SQLAlchemy’s fault.

              I don’t think that’s what they’re trying to say. The article states (emphasis mine):

              In Wave’s codebase, the SQLAlchemy database session is a request-global variable

              The reason they don’t seem to like SQLAlchemy is because it obscures the queries that are being emitted. And I think you’re right in that regard, it sounds like he’s talking about the ORM part.

            2. 3

              Nice essay.

              I recently blogged about something I’ve labeled “cross checking”. Instead of having rather academic arguments about various ways to solve a problem, go solve the problem, the actual business problem and nothing else, using zero or the minimum amount of complexity possible.

              At that point, no matter how you actually deploy, you’ll know in the back of your mind how far away your architecture is from the absolute minimum. This knowledge becomes a kind of “North Star”, allowing teams and orgs the ability to navigate frameworks and tools questions later on. It’s an exercise that should be repeated at intervals.

              This also allows orgs at a larger scale the ability to look at how much tech a new startup competitor can pick up and deploy if they decide to enter your market. That’s not the kind of thing you want to learn by watching it happen. Better to manage that kind of risk as aggressively as possible.

              1. 2

                Tbh, ‘subtle data-integrity bugs’ is not what I want to hear from an application that handles money. Hopefully they figure out the SQL transaction issue.

                1. 1

                  I think a more accurate title would be “Some benefits of simple software technical architectures”. I’m old enough to remember when there were choices as to how one “architected” functional requirements and domain constraints, not just non-functional requirements.

                  A simple “crud” app that adds and subtracts numbers? 70 engineers for that? Sorry I call that ball out of bounds! I suggest that there actually is complex “behavior” beyond “create, read, update and delete” as well as very complex constraints on that behavior. Personally I’d love to know how those are modeled and implemented.

                  That behavioural. complexity can certainly be implemented on top of a simple technical architecture rather than a complex one, but I do think that “technical” is a word required.