result = []
for frob in Frob.get_all(where=something) {
if frob.foo = expected {
result = {
frob: frob,
quux: Quux.get_all(where=some-query-using-frob)
}
results.append(result)
Basically, the idea is that you fetch some data and check some condition or do some calculation on it, then fetch more data based on this condition/calculation. This entire thing could be a single logical process.
The only reason there's a separation of concerns here is because some of this is done in the database and some in the application. Logically, its still part of the same calculation.
But the ORM hides this distinction and makes both the part that runs in the database and the part that runs locally look the exact same and super easy to intermingle. Worse still if you access properties on your ORM-result-object which actually trigger further queries to get. It looks like a field access, but is actually a database query. I've seen this cripple performance.
In many cases, if you step back and don't think about it in terms of application code, but rather the data access and transformations that you want to achieve, then it can be rewritten as a query (joining related data in as needed etc). At the very least, it makes you aware of what the boundaries are.
I'm not saying that scrapping the ORM will magically make the problems go away and I know people also write terribly intermingled application and database logic when using SQL, but at least the boundary is more explicit and the different sides of the boundary actually look different instead of just looking like application code.
My point isn't that there's a silver bullet, but that we can nudge and encourage people to write better code by how the languages/libraries/tools structure solutions.
I'm also not necessarily saying that we have to use SQL instead of an ORM, that's just one possible suggestion that I personally find works due to the mental separation. I'm sure you can design ORM's that make the boundaries more explicit, or design frameworks that encourage thinking about application boundaries more explicitly. Same as how I'm not actually suggesting to get rid of OOP, just... if most people's OOP is so-called "Bad OOP", then we need to think about how to improve OOP, because changing "most people" is just not going to happen.
Yeah, I understand what N+1 queries are and how many ORMs make them too easy.
For me, ORMs become a problem when they're an excuse to avoid learning SQL. If you understand SQL, you will probably understand why the example you give is a bad idea. If you don't, you won't. I'm speaking from the point of view of having written, at this point, thousands of lines of SQL at minimum, and having decided that it's not how I primarily want to access data in the applications I write. The ORM queries I write are written with rough knowledge of the SQL they generate, and I try to be very careful with query builders to avoid the exact case you bring up.
I think LINQ in C# does a pretty good job of bridging this gap, actually. It could be better, but it discourages looping and encourages the declarative style that efficient SQL requires.
I think this is the problem that tools can’t solve. If you want to interface with a database, you need to know how a database works, regardless of what tools you use. I like using ORMs, and I think I write good ORM code. But I also think that I know quite a bit about how databases work, and that I’d be incapable of writing good ORM code if I didn’t.
If you give a novice developer an OOP assignment, they’re likely to struggle with the learning curve, and likely to ultimately create something that has a lot of unnecessary complexity. If you give a novice developer MEAN assignment, they’ll create something that “works” a lot easier. But it’ll likely be full of bugs created by not understanding the underlying problems that the framework is simply not forcing you to address.
Which is what I think these “simple” frameworks do. Allow you to create working features without necessarily considering things like consistency and time complexity. I also think it’s why things like Mongo have been slowly adding more ACID consistency, and schema design features. Because people are coming to realize that those are problems that simply can’t go unaddressed. And why ORMs and things like GraphQL have become so popular, which to me look remarkably similar to the structured approach of OOP design patterns.
The only reason there's a separation of concerns here is because some of this is done in the database and some in the application. Logically, its still part of the same calculation.
But the ORM hides this distinction and makes both the part that runs in the database and the part that runs locally look the exact same and super easy to intermingle. Worse still if you access properties on your ORM-result-object which actually trigger further queries to get. It looks like a field access, but is actually a database query. I've seen this cripple performance.
In many cases, if you step back and don't think about it in terms of application code, but rather the data access and transformations that you want to achieve, then it can be rewritten as a query (joining related data in as needed etc). At the very least, it makes you aware of what the boundaries are.
I'm not saying that scrapping the ORM will magically make the problems go away and I know people also write terribly intermingled application and database logic when using SQL, but at least the boundary is more explicit and the different sides of the boundary actually look different instead of just looking like application code.
My point isn't that there's a silver bullet, but that we can nudge and encourage people to write better code by how the languages/libraries/tools structure solutions.
I'm also not necessarily saying that we have to use SQL instead of an ORM, that's just one possible suggestion that I personally find works due to the mental separation. I'm sure you can design ORM's that make the boundaries more explicit, or design frameworks that encourage thinking about application boundaries more explicitly. Same as how I'm not actually suggesting to get rid of OOP, just... if most people's OOP is so-called "Bad OOP", then we need to think about how to improve OOP, because changing "most people" is just not going to happen.