7 ms·
Don't use just one ORM and then declare "ORM's are stupid". The "object = None" / "object_id = None" issue illustrated here is certainly not a mistake every OR
by zzzeek 14y ago
Don't use just one ORM and then declare "ORM's are stupid". The "object = None" / "object_id = None" issue illustrated here is certainly not a mistake every ORM makes.
- InclinedPlane 14y agoDo you have an example of an ORM which is not in some fundamental way "stupid"? I haven't found one yet, but I'd love to know one existed somewhere.
- zzzeek 14y agoUntil we've attained AI, all software can be said to be "stupid". Google is stupid. Relational databases are stupid, SQL is stupid. None of it works without human intelligence actively directing it to do work for us. Why single out ORMs?
- PommeDeTerre 14y agoYou're contradicting yourself. Your first comment indicates that it's wrong to label ORMs as "stupid". Yet in this latest comment, you've labeled all software (which includes ORMs, of course) as "stupid". Like the other commenter requested, can you provide an example of an ORM that isn't "stupid"? Your initial comment makes it sound like you've worked with at least one that isn't. We're curious to learn about which these may be.
- zzzeek 14y agoThe word "stupid" here is ambiguous, so can be interpreted as, "stupid", "it's stupid to use them" (I disagree), or "stupid", "they don't necessarily understand your intent" (this applies to all software), "stupid", "simple issues are made more complicated than they should be, to an unreasonable extent" (this is a problem that varies to a significant degree based on the ORM in use and cannot be generalized based on the experience of just one ORM). Without the benefit of the speaker's words here it's hard to tell, though the only backing evidence given in these slides for "ORMs are stupid" is a trivial issue that not every ORM has, so that's IMO not a good argument. View my profile for further detail.
- PommeDeTerre 14y agoYou know, you could've just directly mentioned SQLAlchemy earlier...
- zzzeek 14y agoI don't like making my posts look like plugs for my own stuff, though I guess it's unavoidable....
- espeed 14y agoIn these type of discussions, it's not a plug -- it provides examples and evidence useful for teaching, which can light a path to a better way. As Abelson and Sussman point out in SICP, "Computer language is not just a way of getting a computer to perform operations but rather that it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute" (http://mitpress.mit.edu/sicp/front/node3.html http://mitpress.mit.edu/sicp/front/node3.html). The software we write is a codified expression of what we think, distilled into a working example that can elevate a discussion from theoretical-based to evidenced-based. Those who have devoted time to think through an issue deeply and have codified their thinking into software would be doing a disservice by not referencing it.
- white_devil 14y agoThe problem with ORMs seems to be that they're a leaky abstraction. I've been very happy using SQLAlchemy for quite a while now, but I'm intentionally only using the SQL Expression API. Based on my experience with Hibernate, there's always something you want to accomplish that necessitates circumventing your ORM. Not only that, but typically you end up balancing between stuff being unavailable because of lazy-loading, and one pageview taking 30 seconds because the ORM collected all the dependencies.
- zzzeek 14y ago> The problem with ORMs seems to be that they're a leaky abstraction. I disagree it's a problem. going back to Joel again (!) : "All non-trivial abstractions, to some degree, are leaky." I talk about this a lot in this particular talk: https://www.youtube.com/watch?v=E09qigk_hnY https://www.youtube.com/watch?v=E09qigk_hnY Hibernate was a great influence on me but I like to think that it only introduced some ideas in rough form that we've all had many years to improve upon. The ORM will of course introduce new issues to deal with but this is because it's taking care of a vast amount of persistence code you no longer have to write, and applies a consistency to that persistence logic that would be extremely difficult to achieve without using tools.
- nolok 14y agoThat's called arguing for the sake of arguing ... OP says one ORM is bad so all of them are, you say no some are nicely made (which I agree with), parent ask for a specific example you would recommend and you answer by nitpicking on a single word in his message, one that he even put in quotes himself. And then you finish with a question about something that parent didn't even say or infer. Either you have an example and you provide it, or you don't and you say so, but your comment was unnecessary and unwanted. (and so is mine, but I've seen so many of those on HN lately that I just broke and wrote that rant)
- zzzeek 14y agosee my other comment to PommeDeTerre.
- lutusp 14y ago> Until we've attained AI, all software can be said to be "stupid" ... None of it works without human intelligence actively directing it to do work for us. You've implicitly defined AI as a level of intelligence that doesn't need human oversight to function. That level doesn't exist yet, but that doesn't mean AI doesn't exist -- it just has a different definition than the one you're using. Consider Watson (the Jeopardy contest computer lately in the news) -- it can beat the best Jeopardy players, but it's completely unable to function if given a different task or deprived of human oversight. Notwithstanding that limitation, most people will claim it's an example of AI.
- InclinedPlane 14y agoSoftware is a tool, ORMs are tools. I don't need a tool to do my work for me, I just need it to work well for whatever job it's for. A "stupid" hammer would be one that is just a rock with a hole in it loosely fitted over a stick that fits in the hole with nothing but friction to hold it on. A "stupid" farm tractor would be one that gets 15 mpg most of the time except when it's used during a full moon between 10am and noon, in which case it gets 1 mpg. Most ORMs are indeed stupid. They often produce completely surprising results at the least opportune moments. They are high maintenance tools that require constant supervision to ensure that you haven't accidentally made some changes which causes something crazy to happen in the ORM. It's about the principle of least surprise, which ORMs often fail horrifically at.
- mythz 14y agoThere are several Micro ORMs for .NET: http://www.servicestack.net/benchmarks/#dapper-benchmarks http://www.servicestack.net/benchmarks/#dapper-benchmarks That don't try to handle hidden-magic-state and lets you easily access via Raw SQL if you need to do complex queries. Many don't try to abstract anything and are simply extension methods over the underlying IDbConnection (so you never lose any flexibility), i.e. they simply exist to remove the tedium boilerplate of mapping RDBMS results back into POCOs.
- pbz 14y agoAnd if you want to take it to the "next step" and not rely on strings, having everything compiled and checked by the compiler, while staying low level: http://bltoolkit.net/ http://bltoolkit.net/ or https://github.com/linq2db/linq2db https://github.com/linq2db/linq2db
- craigkerstiens 14y agoYou should take a look at the ORMs that are considered a bit more at the top of their class. In the Python world SQL Alchemy in the Ruby world Sequel. While you can't judge all ORMs by looking at a few these do offer a better impression of what an ORM can do for you.
- lucian1900 14y agoSQLAlchemy has several explicit layers of abstraction, the first of which is an AST for all of SQL. The ORM is entirely optional.
- Aqueous 14y agoWhy not just write the SQL?
- lmm 14y agoPoor tool integration, nonexistent library ecosystem, and the advantages of a single-language codebase.
- drdaeman 14y agoThe only problem I see, is we can't rewrite SQL. I.e., in pseudocode: query = SQL("SELECT * FROM entities WHERE owner = ?", owner=me) ... if some_condition: query = query + SQL.WHERE("OR public = TRUE") ... if other_condition: query = query + SQL("LEFT JOIN things AS t" " ON t.entity_id = entities.id") \ + SQL.WHERE("things.value > 0") ... my_nice_list_of_results = run(query + SQL("LIMIT ?", count)) This should be technically possible, but I haven't seen any library that does it.
- memset 14y agoI have always wondered why people have an aversion to stored procedures. They are a programming language in themselves, so you could pass all of your parameters (owner, some_condition, other_condition) into a proc and, depending the logic, return a different cursor to a different query.
- zzzeek 14y agoit's because the stored procedure development model lacks the tools in order to make integrating with an application-level domain model simple. You end up needing to write not just one persistence layer, that of marshaling your object model to and from SQL statements, but two - all the SQL statements behind your stored procedure layer, and a second to move all the data between the SPs and your object model. To make matters worse, the stored procedures must be written completely by hand without the benefit of any in-application schemas to help compose statements. One reason for the variety of opinion on this is that different developers make more or less use of domain models in the first place. Those who are accustomed to writing all SQL completely by hand with no helpers at all, and not working with a domain model tend to view the stored procedure approach as equivalent. Those who are accustomed to having at least some simple marshaling layers like a construct that generates an INSERT statement given a list of column names see the SP approach as more tedious since simple techniques like that are usually not easily available, at least in more old school SP languages like TRANSACT-SQL and PL/SQL. All of that said, I do think this is a problem that can possibly be solved. Postgresql allows SPs to be written in many languages, including Python. I have an ongoing curiousity about the potential to integrate a Python-based object relational system into a stored procedure system. But it might end up looking like EJBs.
- k4st 14y agoThe SQL generated appears correct, unless the underlying database can guarantee that all foreign key constraints are met. That is, I consider this a failure of the user of the ORM to appreciate that the two invocations of filter are not identical. In the former case, the query is verifying that the object_id field cannot be used to find a foreign object--regardless of the value of object_id. This is exactly what it is asked to do. In the latter case, the query is simply verifying that object_id is NULL, which is exactly what it's asked to do.
- zzzeek 14y ago"other_id" and "other" here refer to two different ways of referring to a many-to-one reference between "somemodel" and "othermodel". Asking for rows of "somemodel" where "object_id" is None is the exact same thing as asking for rows from "somemodel" where its reference to "object" is None. Both should produce the same query, the simple one without the JOIN. The query with the JOIN is completely wasteful and not at all correct - it does a LEFT OUTER JOIN to the remote table, only to filter on those rows where the remote table has no match; but this is already obvious from whether or not "somemodel.other_id" is NULL.
- ikawe 14y agoYou're right in that they are largely the same action, but consider this case: An Owner is deleted without setting the pets.owner_id to NULL. So now there's a row in Pets with an owner_id referring to an Owner that doesn't exist. These two queries will (rightfully) return different things in this case. One will return The Pets who have null for an owner_id. The other will return the Pets whose owner_id is NULL AND those who do have an owner_id, but it doesn't reference an existing row in Owner.
- zzzeek 14y agoOK, you're right in that owner_id can refer to a nonexistent entry, if the schema both doesn't make correct use of constraints and is also referentially corrupt. Designing the ORM to jump through huge hoops to suit the case that the user is using the relational database incorrectly, in such a way that enormous performance overhead is added to the use case as used correctly in the vast majority of cases, is IMO a poor design decision.
- macspoofing 14y agoTrue, but every ORM will make that kind of mistake. You can't just build an object model without paying attention to the SQL layer.
- tmarthal 14y agoObviously there are subtleties to things that may not be apparent, but his example makes sense to me and so does the SQL queries that are generated. The first query is operating at the "object level" and the second is operating at the "attribute level". The first is retrieving the object and checking if it exists, and the second is just checking the parent's foreign key. Not sure that they are really the same query, if you have unenforced foreign keys. This is not "dumb", this is analogous to checking if a pointer is null or that the contents of the pointer are null (which is a distinction that some people want to make).
- avenger123 14y agoDefinitely agree. Using an ORM should not exclude also using direct SQL. It should be both. I believe this brings the best combination. Anytime there is major complexity just drop to normal SQL. The best of both.
- Daishiman 14y agoI think it's more of a case of the developer not having read the ORM documentation; this is a very newbie mistake (although very understandable, true). Now obviously, some people would complain that it doesn't make sense to do the extra join, but then people would be complaining about magical or exceptional behavior. ORM behavior is very predictable about which fields are being queried
- JshWright 14y agoI haven't checked this one either way, but I'm curious what SQL would be if they used the 'right' ORM incantation. filter(object__isnull=True) https://docs.djangoproject.com/en/dev/ref/models/querysets/#std:fieldlookup-isnull https://docs.djangoproject.com/en/dev/ref/models/querysets/#...