Hacker News new | ask | show | jobs
by dkersten 1973 days ago
My problem with these arguments is that its meaningless, if this "bad OO" (or "bad <insert paradigm>") is what most developers write.

Its a big problem I have with ORM's. Every time a discussion about what's bad about ORM's is brought up, there's a multitude of people saying that its just used wrong, written wrong or otherwise done wrong, yet that's basically my experience with every non-toy codebase I've ever worked on as part of a larger team. Telling me that its just done wrong is useless because its out of my hands. Is it the ORM's fault? I argue yes because it encourages that kind of programming, even though its not technically the ORM's fault.

I see it the same with OO or anything else. Is this "bad OO" the type of OO people tend to write? If yes, then OO is the problem. If no, then OO is not the problem.

Personally, I like a mixed approach where I use some OO and a lot of functional. I'm writing a little toy game in C++ from scratch and I have a very flat design, preferring functional approaches where I can, but I have a few objects and even a little bit of inheritance where it makes sense. Sometimes dealing with an object-based API is just more convenient and I won't shy away from using OO principles, but I also don't default to them just because either.

3 comments

But every programming paradigm can be (and perhaps most often is) done badly. They each just create their own set of issues when "done badly". I think it just comes from not properly understanding why you're making certain choices. Deciding to use a design pattern is going to come with a certain set of strengths and weaknesses, so ideally you'd consider your problem and choose design patterns that makes the most of the strengths and minimizes the impact of the weaknesses. But I don't think it's very common to put that much thought into programming decisions, so people will often make a design decision, and then invest their effort into fighting the constraints it imposes, while usually failing to realize the potential benefits of it. OOP can be a perfectly suitable tool to solve a problem, but if you haven't thought about the actual reason why you want to use it, then you're just going to end up creating complicated abstractions that you're not properly benefitting from. ORMs can be great tools to, but if you want to use an ORM, you have to solve your problems using the approaches implemented by the ORM. If a programmer can't/won't do that, then they've just chosen the wrong tool for their problem/the approach they wanted to take to solve it.
Maybe the overall takeaway is that most programmers are bad.
Perhaps. I think a more likely explanation is that it's just not a very professional field. As a field it hasn't been around for very long at all, and it's changed a lot during that period. If it was obvious to tell the difference between bad and good programming, then perhaps things would be different. But I don't think that's obvious at all, and I don't think it's possible to create any meaningful level of agreement in that area. Look at how hard it is to agree on any sort of standard. IETF RFCs take years to process, with the typical outcome being a standard that enough people agreed to publish, but that 0 people faithfully implement.
I have another opinion about that. Most of us don't work in product companies but rather as consultants or in IT enterprise environments. In such contexts the real objective of software development is often the improvement of a process that is enabled by the software. As such the cons of bad software are not immediatly clear to any management layer above the first. Sometimes even the first layer of management doesn't really care until they get the process improvement they want. If the new software produces an increase of 30% in sales then the fact that it is badly written is just of secondary importance: the objective has been met. The fact that bad software quality will hurt maintanance in the mid-long term is often too far in the future for anybody to really care.

As software engineers I have seen that we usually make two mistakes in these cases. We focus only on our craft without taking into consideration the real business objectives of the customer and what he really cares about. We introduce unnecessary complexity just for the sake of it, often adding unnecessary abstractions. In a few words we often make the sin of believing that software is the objective while in most of the cases there is a business objective for which software is just the enabler and because of that we lose focus on what is the right thing to do.

In software product companies code is part of the final product and code quality directly impacts costs and the core business of the company.

I’d still say this is at least partially attributable to not having any real measurements of what “good” software is. At least aside from at a very basic level.

If you want to build a bridge, I’d assume there’s a set of standards it has to comply with. If it doesn’t meet the spec you could explain in very objective terms why the quality isn’t sufficient. If you had to sit in front of the board and explain why you think a piece of software wasn’t built to a sufficient standard of quality, you’re going to really struggle to do that in objective terms. The best you could really hope to do is present a well articulated opinion. Anybody who disagrees with you could present their own opinion, and unless they have a high degree of technical competence, they’re not going to have any objective approach for making judgements about that.

Sure lots of companies prioritize feature velocity over code quality. But I doubt most of them a very well informed about what quality compromises they’re actually making.

In some large Internet Scale firms there were ARBs, Architectural Review Boards. They served this purpose, by having very senior members of staff review proposed architecture and implementation approaches PRIOR to coding occurring. The danger was that over time, this sometimes devolved into the members waiting to just beatdown people presenting to them and being internally "political".
This resonates with me.

In other fields it can be easy to say when a job is done well. There can be clear guidelines. That said, other fields cut corners and do a “bad” job, too. Construction for example. It is probably possible to explain to average Joe why a damp proof course wasn’t installed properly or the insulation used is dangerous and flammable.

Programming as it exists now seems often in service of something else. So a deadline causes cut corners. So in this context a cut corner is fine and “we’ll fix it later”.

I suppose programming differs from a physical thing like construction. Sure you can replace the wiring and install a mezzanine but it’d be insanely impractical.

I’m going off on a tangent now...

Construction is a prime example, especially Home Construction. Just look at the TikTok videos showing horrendous plumbing and electrical work.

Hell, I moved into a house built 3 years ago by a major firm and the ceiling fans were ALL wired wrong, and many of the electrical plugs are upside down.

This is a house that had a specific design model. My presumption is that unskilled labor was brought in to complete work and just did a shitty job.

You can see this sometimes with outsourced programming work or local work that is poorly designed and inadequately tested.

Maybe its true, but that just shifts the blame and doesn't change anything or solve anything. Try as we might, "fixing" programmers just isn't realistic, so the only thing we can do is look for ways to improve the tools to make them encourage better practices.

Going back to the ORM example, I'm cool with just using SQL. The language encourages a style of thinking that fits with databases and it being a separate language makes it clear that there's a boundary there, that its not the same as application code. However, I'd also be ok with an ORM that enforced this boundary and clearly separated query logic from application logic.

As for OOP, I don't know what the solution there is. Maybe there isn't one. I like to use OOP, but sparingly, and at least in my personal code (where I have control over this), its worked out really well. A lot of code is transforming data structures and a functional approach maps really well to this, but for overall architecture/systems and even for some small things that just map well to objects, its great to have OOP too. In my toy game, I use inheritance to conveniently create external (dll/so) modules, but inside the engine, most data is transformed in a functional style. Its working quite well. I'm not sure how you could redesign the paradigms to encourage this though, outside of designing languages to emphasize these things.

>The language encourages a style of thinking that fits with databases and it being a separate language makes it clear that there's a boundary there, that its not the same as application code.

The separation is orthogonal to the data access style used, and you really have to make sure the engineers you're working with understand separation of concerns. I have seen many applications with controllers filled with loads of raw SQL, just as I have seen them filled with lots of ORM query building. If the programmers don't get why that's bad, they will do the wrong thing with whatever tools they have in front of them.

Take this contrived presudocode example:

    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 read somewhere that the amount of programmers in the world doubles like every 5 years. That means that at any given moment, half of programmers have less than 5 years of experience.
I've been programming for 30+ years. I still have less than 5 years of experience in anything that's currently popular.
The biggest problem with intermediate level programmers is their love of hard and fast rules. It's like they have a backpack full of hammers ("best practices") and they're running around hammering everything in sight. For this I feel like it doesn't really matter how much experience you have in an individual piece of tech - the overall amount matters more.
> The biggest problem with intermediate level programmers is their love of hard and fast rules

I think that’s just a problem of dogmatism, which doesn’t necessarily go away with experience.

In order for a programmer to program in many patterns elegantly, one must first have understanding of those patterns and how they are roughly reduced to machine code.

The skill of experiencing trumps the amount of experience.

Bad programmers need to hone their skill to experience in order to become good programmers. The most popular way is to provide them a safe environment to make mistake and learn from it. But the most important way is actually knowing that skill of experiencing and getting out of biases are important, like in this case "if OOP is indeed bad, why is it invented in the first place", and the rabbit hole actually gets interesting from here.

At least that's my take after a few years in the industry.

And yet after 2-3 years they are appointed as "senior" in some of the most developed countries :)
My main point is that the things we use encourage a certain approach and if most people are "doing it wrong [tm]", maybe its not the people's fault, maybe the tools are encouraging wrong approaches.

I mean, sure, you can just say most developers aren't very good, aren't disciplined enough, don't think things through. Maybe its true. But that doesn't solve the problem, it just shifts the blame. You can't fix the people, because its a never-ending problem: move team or company and you're back at square one. Good luck trying to change all the university courses to try and teach better practices.

So if you can't fix the people, the only thing left is to take a long hard look at the tools and see if we can't improve them in a way that encourages better code.

It’s really hard to make a really good ORM.

Except rails ActiveRecord there is probably no one.

Even though AR also has some issues.

Diesel (rust)

Also it's maybe notably by a (former?) maintainer of ActiveRecord, though, I haven't really used RoR but I think the design is probably quite different - Diesel is very much just the SQL with a veneer of Rust, almost FFI wrapper like.

Why should I have to remember to use '.values' instead of 'GROUP BY'; '.filter'/'.except' instead of 'SELECT'? It's not helpful. I frequently have a clearer idea of the SQL I want (I'm certainly no DB expert) and have to make it at least twice as long, install a plugin, or in some cases just can't mangle it into Django. For what?

Diesel is nowhere near being able to fully map SQL to rust. It's ok for relatively simple queries that are typical for OLTP applications. Anything beyond that and you're going to run into trouble.

If you want to do something more OLAP-ish or insert data in bulk, you have a huge problem. SQLAlchemy is far better, even though SQLAlchemy also has its own share of limitations (dealing with jsonb_to_recordset and functions like it for example).

sqlalchemy in Python. Having used both ActiveRecord and sqlalchemy, I'll take sqlalchemy all day everyday.
SQLAlchemy is really special - coming from Django I wasn't convinced initially, but I think the reason it works so well is it doesn't try to hide any magic. It's simply a nice way to represent objects in your database, you still have to explicitly request it to commit / run queries.
I've messed around with activerecord for sqlalchemy :)

https://twitter.com/arundsharma/status/1338596939600781313

My main issue with ORM's is that they encourage you to mix application code and queries (by making it easy and by making the code for both look the same), blurring the boundary between your application and the database.

This is a problem, because there is a real boundary, typically including a network round trip. I've been on way too many projects where ORM-using code would pull some stuff from the database, do some application logic to filter or process the results, then loop and do another query for each result. Instead of doing it in the database query itself using joins (and possibly being able to use indexes for the filtering).

Even when people are very disciplined about this, I find that once you get to non-trivial queries, they become a lot harder to read in ORM code. I tend to have to think in terms of SQL, then translate between that and the ORM code on the fly. Its not so easy.

Sure, you could say all the teams I've ever worked on that did stuff like this are just bad at using ORM's, but after a few experiences like this on different teams, in different companies, with different developers, its time to stop blaming the people and maybe take another look at the tools.

I really feel your pain. This is not yours or ORM concept fault.

There is just no good ORMs out there.

Except ActiveRecord (and maybe mongoose for mongo). And even these 2 are not the best choice for all use cases.

Most ORMs fails because they map one table with one class.
It is really hard - DBIx::Class (Perl) is an example of one of the better ones, in my opinion.
Hibernate and Entity Framework?
Hibernate is ok technologically but it is a usability nightmare. However its reliance on reflection makes me want to stay away from it.
Do you care about performance? In my experience, N+1 queries are impossible to avoid with hibernate (or any JPA framework, generally). But maybe I’m just using it wrong.
See https://vladmihalcea.com/

He has a lot of info on high performance Hibernate and particularly the n + 1 issue.

It should be mostly avoidable.

Thanks for sharing this.

For anyone else interested, here’s one post he has on the problem: https://vladmihalcea.com/n-plus-1-query-problem/

Thanks for digging out this direct link.

I haven't been there for a while but I'm fairly sure there should be a few more.

I haven't found that to be the case. In particular I think expecting the ORM to always do the best thing no matter how you use it is folly, ORMs are a tool that you have to take the time to understand in much of their full complexity.

Some would say this makes them a bad abstraction, but to me, data mapping is going to have to happen somewhere, and I would rather be building on someone else's work to write the data mapping for my applications than do it from scratch. You have to know when the ORM is the right tool to use, and when to drop into plain SQL for your querying, because they do not eliminate the need to write SQL, just reduce it significantly.

We are currently considering moving away from Entity Framework Core. Simple things work fine, but it generates ridiculous queries if stuff gets more complex.
Many ORMs are going to have trouble at some point when you start making more complex queries. I believe using an ORM well is largely in understanding the balance between when its tradeoffs are acceptable and when they are not. Per the other reply, I would probably start with EF Core in new applications, but would not hesitate to add Dapper or just plain SQL with ADO if I saw the need.
Is there any reason why it needs to be either/or, or are you suffering from OCD light like so many others of us? ;-)
> My problem with these arguments is that its meaningless, if this "bad OO" (or "bad <insert paradigm>") is what most developers write.

Only if that's more true than “bad <foo> is what most developers write in paradigm <foo>” where <foo> is the presented alternative paradigm, otherwise we’re comparing the platonic ideal of <foo> against real world OO.

Sturgeon’s Law may not be quantitatively precise, but it addresses a real qualitative issue that must be considered.