▲ | ryanrasti 3 days ago | |
Really nice summary of the core challenges with this DSL/code-as-data pattern. I've spent a lot of time thinking about this in the database context: > No printf debugging Yeah, spot on. The solutions here would be something like a `toSQL` that let's you inspect the compiled output at any step in the AST construction. Also, if the backend supports it, you could compile a `printf` function all the way to the backend (this isn't supported in SQL though) > No "natural" control flow in the DSL/tracing context Agreed -- that can be a source of confusion and subtle bugs. You could have a build rule that actually compile `if`/`while`/`for` into your AST (instead of evaluate them in the frontend DSL). Or you could have custom lint rules to forbid them in the DSL. At the same time -- part of what makes query builders so powerful is the ability to dynamically construct queries. Runtime conditionals is what makes that possible. > No side effects in the DSL/tracing context because that's not a real "running" context Agreed -- similar to the above: this is something that needs to be forbidden (e.g., by a lint rule) or clearly understood before using it. > Is this all just necessary complexity? Or is it because we're missing something, not quite seeing it right? My take is that, at least in the SQL case: 100% the complexity is justified. Big reasons why: 1. A *huge* impediment to productive engineering is context switching. A DSL in the same language as your app (i.e., an ORM) makes the bridge to your application code also seamless. (This is similar to the argument of having your entire stack be a single language) 2. The additional layer of indirection (building an AST) allows you to dynamically construct expressions in a way that isn't possible in SQL. This is effectively adding a (very useful) macro system on top of SQL. 3. In the case of Typescript, because its type-system is so flexible, you can have stronger typing on your DSL than the backend target. tl;dr is these DSLs can enable better ergonomics in practice and the indirection can unlock powerful new primitives |