|
| 1 | ++++ |
| 2 | +title = "Stop using your app query builder for analytics" |
| 3 | +description = "There are better alternatives." |
| 4 | +date = 2026-01-18 |
| 5 | +[taxonomies] |
| 6 | +tags = ["opinion", "sql", "analytics"] |
| 7 | ++++ |
| 8 | + |
| 9 | +## Context |
| 10 | +A few years ago (in 2022 I believe), I had a disagreement with an interviewer debriefing one of my take-home assessment. We were discussing the usage of raw SQL in a codebase, and I believe my position cost me the role (or, alternatively, the way I expressed my disagreement did). |
| 11 | + |
| 12 | +We were basically arguing over a query that was doing a bit of filtering, grouping, and formatting data. This query took no parameter, and considering the query was used to extract analytics, I decided to go for raw SQL. |
| 13 | + |
| 14 | +This is relatively easy to do with many frameworks, and it's [straightforward in Elixir with Ecto][0]. |
| 15 | + |
| 16 | +I think I also failed at expressing stronger arguments at the time other than "You don't need the added complexity of an ORM, for a simple query without arguments." and if I recall correctly, the person I was talking to was just saying "it's safer". |
| 17 | + |
| 18 | +I did a bit more work related to analytics since then, and I gathered stronger arguments. I'll keep it short, but here they are :) |
| 19 | + |
| 20 | +### Your app query builder is another layer of complexity |
| 21 | +This is literally another DSL on top of another DSL (which is, in this case, SQL). |
| 22 | + |
| 23 | +A DSL is a system, and each system comes with some overhead, the possibility of oversights (such as N+1 queries) and bugs related to the library. |
| 24 | + |
| 25 | +It also comes with limitations. I recently saw that a PHP ORM didn't have support for the `WHERE x OR Y` syntax for its query builder. I wouldn't be surprised if PostgreSQL's `with` statements weren't supported in some libraries even to this day. |
| 26 | + |
| 27 | +### SQL is the domain language for data queries |
| 28 | +A query builder also forces you to `think` using its grammar and semantics, which may be very different than the underlying database language. |
| 29 | + |
| 30 | +Your Database Administrator or DevOps may not know this language, which would be a problem if they had to debug those by themselves. |
| 31 | + |
| 32 | +And finally, you may eventually have or want to switch libraries, or languages, and you would have to port your queries over. |
| 33 | + |
| 34 | +Arguably, you could also have or want to switch to another database, with its own DSL. But I assume this would be less likely to happen, at least for a company's typical "core" records (eg. sales, customers, ...). |
| 35 | + |
| 36 | +### You can do better than writing analytics inside your codebase |
| 37 | +I recently worked on a project where we were building a dashboard, with analytics queries written with our ORM. |
| 38 | + |
| 39 | +The flow went this way: |
| 40 | +* A developer would write those queries and merge them to the trunk, |
| 41 | +* I would try to use them, write tests to check those were valid, |
| 42 | +* Potentially reported bugs, and had to wait a bit before the fix came up, |
| 43 | +* Had to implement various export modules, without knowing if the output was correct for the business, |
| 44 | +* The person doing the QA would report to me, and I would then have to convince the person who wrote the queries that there was a problem there, |
| 45 | +* I would then have to adapt my modules to the potentially new format, and adapt all of my tests. |
| 46 | + |
| 47 | +This was totally uneffective. A lot of those queries weren't even tested, and the debugging was painful and slow. |
| 48 | + |
| 49 | +Arguably, some of the things that went wrong could have been avoided by having just one developer do the whole job. |
| 50 | + |
| 51 | +But I think the best course of action would have been to do it this way: |
| 52 | +* Take the time to spin up a [Metabase][1] instance (or similar), |
| 53 | +* Write queries, **and** validate them on a production replica, |
| 54 | +* Validate the output with the QA team, |
| 55 | +* Implement a client that would query Metabase's API, |
| 56 | +* Implement the export modules. |
| 57 | + |
| 58 | +Boom. Smooth. |
| 59 | + |
| 60 | +And this isn't less safe. Arguably, a bit longer to setup, and that Metabase client may have to be implemented, but this would have been so easier to debug. |
| 61 | + |
| 62 | +Thank you for reading me. Please let me know what you think. |
| 63 | + |
| 64 | +[0]: https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.html#query/4 |
| 65 | +[1]: https://www.metabase.com/ |
0 commit comments