4 ms·
> In any sufficiently complex application, something like a query builder that allows different parts of the application to work together to lazily compose quer
by mvdtnz 3y ago
> In any sufficiently complex application, something like a query builder that allows different parts of the application to work together to lazily compose queries
I don't see this as a given and I don't accept it in my own applications. If you need data, go to the data access layer. If it doesn't provide you what you need, build a new repository / provider / whatever your pattern is.
Whether it's an ORM or a home-built query compositor or whatever, one thing I know from experience is that once your application is "sufficiently complex" that you start to (incorrectly) believe you need this, your application has become too complex to use it reliably.
You absolutely will be mistakenly evaluating these builders in the wrong layers, iterating results without realising you're generating N+1 queries, etc.
You don't need an ORM.
- markkanof 3y agoWhy are a data access layer and an ORM mutually exclusive? An ORM is just an abstraction over your database. You might find use in it as a tool to access your database but contain the use of the ORM to within your data access layer.
- jakelazaroff 3y agoFollowing this advice too closely and your application logic starts leaking into your data layer. One simple example is when you need to make atomic changes to two different types of entities. In the data layer, this is usually trivial — just run two queries within a transaction — but you need to expose a function that boils down to `updateBothAandB`. Rinse and repeat enough times and your data layer is a soup of business logic.
- mvdtnz 3y agoThere are patterns to resolve this. Depending how you structure your DAL, your data access classes can provide transaction handles. It's a data access layer, you don't need to abstract away the fact that you're dealing with a database.
- paulryanrogers 3y agoIME young businesses evolve so quickly too much abstraction is a higher risk that some bleeding among DAL and business rules.
- edgyquant 3y agoHow is this not just a hand rolled ORM?
- JohnBooty 3y agoAn ORM is a specific kind of data layer. It is general-purpose, and as the name suggests, it is an Object-Relational Mapper whose primary purpose is to map relations to objects and vice-versa. So no, bespoke data access layer code is not an ORM.
- jakelazaroff 3y agoI mean, yeah, but the patterns all look like the thing you said you don’t accept in your own applications: “something like a query builder that allows different parts of the application to work together to lazily compose queries”.
- jupp0r 3y agoExactly, in my opinion, separating your business logic from your data access layer completely is futile. You will need to either have business logic in your data access layer or fine grained query controls (when to add a filter clause, when to execute a query, what should go into a transaction, etc) in your business logic for performance reasons. This is OK, it's incidental complexity.
- lmm 3y ago> I don't see this as a given and I don't accept it in my own applications. If you need data, go to the data access layer. If it doesn't provide you what you need, build a new repository / provider / whatever your pattern is. Whichever layer you put it in, you need a way to compose two query fragments. Otherwise you have to write N*M queries manually instead of N+M query fragments. Either you use an ORM to help you with this or you don't, with all the usual tradeoffs about using a library or not. But you still have to solve the problem. (Or you do a lot of tedious copy-paste work - with all the usual tradeoffs of that)
- jayd16 3y agoWait, why does every query fragment need to compose with every other? What are the N and Ms here?
- Spivak 3y agoSay you create a nice little utility function that makes a call to the db func1 and you write func2 that also makes a db query. If you have a func3 that needs func1 and func2 conceptually your options are: * Accept that this will just be two trips to the DB. * Write a new function func12 that writes a query to return all the needed data in one query and use that instead. * Have your tool be able to automatically compose the queries. If you do with the second option you have to do that with every combination of functions that end up being used together which is multiplicative in general.
- jayd16 3y agoWell sure but that not necessary for every combination of every call. Most likely those types of combinations are rare.
- preseinger 3y agousually, every interaction with your database is its own unique code path and query it's pretty rare for queries to be dynamically composed from arbitrary sub-queries if this is a problem you need to solve then ORMs certainly make more sense, but even in this case I find query builders to be more effective the interface between the application and the DB is actually a string! it's not an abstract data type, it doesn't benefit from being modeled by types