1. Examples (SQL-First Approach)
If an application is composed of various SQLs when interacting with the database, it may grow to have several scenarios such as the following:
1.1. Complexity Level 1
In the most basic form we have maintainable queries via query-builder:
1.2. Complexity Level 2
The following tries to do two separate LATERAL JOIN
's and Json Aggregate
's:
Complexity increases and it takes developers effort to understand what's going on.
1.3. Complexity Level
The following is taken from a deprecated project, it starts to be unmaintainable even with comments that's trying to explain what's happening:
-
You need to have the knowledge how
WITH some_table AS (SELECT ...)
works and how to achieve this in other query-builder framework.
-
Plus we still have lateral joins and json aggregates there.
2. Problems of the SQL-First Approach
-
SQL statements itself, by nature, are not easily readable compared to traditional programming language, even there are query builders.
You may have subqueries, may have
case if then else end
, may have tricky use ofSQL
functions, that nest into theSQL
statement several times. -
Long SQL is hard to debug, we cannot add a breakpoint to investigate the data.
- Complex and tricky SQL can bring huge complexity to the project, which also increases mental cost for other developers to understand and modify it1.
3. Short Takes From Native SQLs
There are indeed cases where native query is necessary for performance such as batch-insertion, or special queries for dashboard. But we can avoid them when they are not necessary.
We need to be careful in the decision of whether or not to use query builder in a project.
-
In Nodejs world there are
Kysely.js
orPrisma-Kysely.js
Knex.js
-
In Java/Kotlin world there is
-
JOOQ
-
-
In Golang world there is
Go-Jet
4. Footnotes
- If you are simply a one-man band, do whatever you want!↩