6 ms·
The author is right about ORMs. They are ridiculously over engineered solutions. (My experience is largely with Django and SQLAlchemy ORMs) As soon as you want
by skrtskrt 6y ago
The author is right about ORMs. They are ridiculously over engineered solutions. (My experience is largely with Django and SQLAlchemy ORMs)
As soon as you want to do something that's not already perfectly built in, everything becomes a mess of impenetrable hacks. Autogenerated Django migrations are unstable and often need to be edited to to be correct or make any damn sense.
It also encourages to people to blur or just straight up stomp on the line between ORM objects - tightly coupled to your database - and business-logic objects (entities, usecases, whatever). It's the Django recommended approach, called "fat models" and it leads to ridiculous levels of coupling and impenetrable ball-of-mud code.
Just write SQL and marshal it into business objects. I'm actually quite fond of doing this with the SQLAlchemy Table & Query APIs, they do most of the marshaling for you.
In Go I just write the raw SQL.
More generally regarding OOP: I have never seen any good come from more than one layer of inheritance.
- dnautics 6y agoAlways prescribing raw sql is dangerous: You typically want something managing your sql queries if there's user input because scrubbing out SQL injections is hard and it's not something you should be 'rolling your own'
- skrtskrt 6y agoYes, I'm really talking about using libraries that let you pass parameters into a statement, and have some level of protection against injection.
- dnautics 6y agoI was just reacting to this, which is confusing given your response. > In Go I just write the raw SQL. But in general I agree with you about ORMs (I do not use them). I'm just pointing out that when the easiest/most popular library to reach for to protect yourself against injection is an ORM, it's understandable to use it.
- winstonewert 6y agoI presume that when somebody says raw sql they mean are using parameters and not just building strings.
- tempodox 6y agoYou should use ODBC or one of its siblings anyway. Never use printf() or raw string concatenation for SQL queries yourself.
- dionian 6y agoBut that is the tradeoff of ORMs. Black box with free stuff but more complexity. Sometimes (usually?) it does not make sense to use them.
- skrtskrt 6y agoOf course the biggest gain of ORMs is initial dev speed. If you're going to stand up a business in a week or a month, Django ORM and its migrations are going to get you a pretty darn good solution without spending hours and hours thinking about your RDB design and handling many-to-many relationships "by hand".
- mnm1 6y agoYeah, why spend hours on the most important part of the application and likely the most important part of the business when you can gloss over with with an ORM and not worry about designing the database until it comes back to bite you in the ass when you can no longer grow your business because of the incredibly stupid thing you did which is not designing your database. Frankly, those businesses deserve to fail if this is the kind of idiocy that drives their decisions. But hey, we got the app going really quickly before going bankrupt.
- zbentley 6y agoI suppose they deserve the same fate if they didn't get security right from day 1? Or accessibility? Or monitoring? Analytics? GDPR compliance? Etc.? Businesses are confronted with different problems at different times. Insisting that everything be solved/designed perfectly up front is silly.
- mnm1 6y agoNone of those things can even remotely compare to the importance of the database design for most software businesses, especially ones just starting out. Most of them can also be addressed later in the company's life unlike a bad database design.
- 6y ago
- 3pt14159 6y agoI like certain aspects of Django, but Rails got models and migrations better. Writing raw SQL for everything gets old, and I'm someone that loves SQL when it's the right call for the job. And I agree with you on inheritance. One level max for production code, one additional level for tests that need to change a method here or there to get them to work. That's it.
- andreareina 6y agoI get that, and I'm comfortable writing raw SQL but as the system grows larger and requirements change I inevitably run into the fact that raw SQL doesn't compose. For me the query builders hit that sweet spot of mapping almost one-to-one to raw SQL, while giving me composition when I need it.
- platz 6y ago99% of the time you should'be be composing SQL. If you need composition at the DB level, that is what Views are for.
- treis 6y agoI'm not sure why you think we shouldn't be composing SQL. What about for cases like: User.banned.posts.flagged where we want all flagged posts from banned users. Posts.flagged.today where we want all flagged posts from today User.created_today.posts.flagged where we want all flagged posts from users created today
- platz 6y agoOr you could just create a View for flagged posts and join on that as appropriate, no ORM needed. There's probably some room for limited compositional SQL, but there are ways to get that without a full ORM, given your type system is expressive enough.
- fennecfoxen 6y ago> As soon as you want to do something that's not already perfectly built in, everything becomes a mess of impenetrable hacks. Once upon a time I worked with a lovely Perl system (!) (yes! Perl!) that used Rose::DB. The main parts of Rose weren't really special in any particular way; the part that was good was that you were provided with rather effective tools for running your own raw SQL queries if you needed to. Of course the bigger problem with ORMs in OOP isn't raw SQL management. It's the fact that the naive approach to OOP and the approach all the frameworks give programmers looks like "active record pattern" and "fat models". The active record instances can be found all over your code, usually leaking some encapsulation violation wherever they're used, and the fatness of the model usually means that the models also accumulate various concerns from parts of the app that don't belong on the models. Many programmers who approached OOP in an ad-hoc manner aren't even aware of patterns like "entity-component-system" and sometimes have strange ideas of what you're supposed to call a "service". > I have never seen any good come from more than one layer of inheritance. Good OOP is compositional and may have a lot of "has-a-strategy" and "implements-an-interface" patterns but usually only a very few "inherits-from" patterns. OOP tools like strongly-typed systems are there to bring you clarity and safety as you move data from your "query XYZs", "plan some XYZ operations", "execute XYZ operations", and the actual system interfaces to perform the operations.
- vsareto 6y ago>As soon as you want to do something that's not already perfectly built in, everything becomes a mess of impenetrable hacks. Use the ORM for perfectly built in things, but also use raw SQL when it's not.
- GordonS 6y agoThis is a pattern I've used before with dotnet, and I think it works quite well. Generally we start with Entity Framework Core, because it's well known and let's us compose and execute queries really easily (I should add we always use a "code first" approach; the actual database is created carefully by us, not the ORM). For some apps, you need to do more complex stuff, such as use composite keys, duplicating rows, etc - while this might technically be possible with EF Core, it's horrible in practice. Also in some cases you just can't coax EF to generate a performant query. In these cases we either add a view, or we add a micro-ORM into the mix, like Dapper - you basically write the SQL yourself, but Dapper helps marshal data from the database to your classes.
- noisy_boy 6y agoHaving used Django's ORM, SQLAlchemy and JPA (via Spring Boot), it depends on the ORM. E.g., JPA's automatic query generation[0] is very convenient while still allowing plenty of options for handcrafted SQL, if needed. I'm the kind of person who enables logging of ORM generated SQL so that I can see exactly whats going on under the hood; so far, many hours saved with very few complaints. This assumes a well defined database model - if that has issues, all bets are off. [0]: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-creation https://docs.spring.io/spring-data/jpa/docs/current/referenc...