13 ms·
OO code for domain modeling might be, to date, the single greatest source of disillusionment in my career. There are absolutely use cases where it works very w
by bunderbunder 2y ago
OO code for domain modeling might be, to date, the single greatest source of disillusionment in my career.
There are absolutely use cases where it works very well. GUI toolkits come to mind. But for general line-of-business domain modeling, I keep noticing two big mismatches between the OO paradigm and the problem at hand. First and foremost, allowing subtyping into your business domain model is a trap. The problem is that your business rules are subject to change, you likely have limited or even no control over how they change, and the people who do get to make those decisions don't know and don't care about the Liskov Substitution Principle. In short, using one of the headline features of OOP for business domain modeling exposes you to outsize risk of being forced to start doing it wrong, regardless of your intentions or skill level. (Incidentally, this phenomenon is just a specific example of premature abstraction being the root of all evil.)
And then, second, dynamic dispatch makes it harder for newcomers to figure out the business logic by reading the code. It creates a bit of a catch-22 situation where figuring out which methods will run when - an essential part of understanding how the code behaves - almost requires already knowing how the code works. Not actually, of course, but reading unfamiliar code that uses dynamic dispatch is and advanced skill, and nobody enjoys it. Also, this problem can easily be mitigated with documentation. But that solution is unsatisfying. Just using procedural code and banging out whatever boilerplate you need to get things working using static dispatch creates less additional work than what it takes to write and maintain satisfying documentation for an object-oriented codebase, and comes with the added advantage that it cannot fall out of sync with what the code actually does.
Incidentally, Donald Knuth made a similar observation in his interview in the book Coders at Work. He expressed dissatisfaction with OOP on the grounds that, for the purposes of maintainability, he found code reuse to be less valuable than modifiability and readability.
- sqeaky 2y agoThis is a strong argument against inheritance, but that isn't everything about OOP. Just one well supported advanced abstraction (That I would also argue should be rarely used.) I would argue that just having strong type system and bundling methods with data gets you the vast majority of the usefulness of OOP. Liskov, Open/Closed, Message Passing, and other theoretical abstractions be damned. EDIT - Where are the good places to use inheritance? There are only a few I can think. One is when you are trying to create a system that inverts dependencies by allowing a plugin system or follows some sort of nuanced workflow that others might want to "hook into". But that isn't the only way to do that, maybe other ways would be better like passing in functors. Another situation I have seen recently is when creating a kind of data or messages that differ only by type and maybe a few small pieces of behavior and they are all known up front.
- moth-fuzz 2y ago> One is when you are trying to create a system that inverts dependencies by allowing a plugin system or follows some sort of nuanced workflow that others might want to "hook into". I’m fairly certain that’s the use case of inheritance - at least in the Simula tradition. Classes as a means of lifetime management, moving parts that have well defined steps of operation (methods), and interchangeable parts (subtypes) which you can more or less slot into the larger system (polymorphism). It’s easier to think about classes not as nouns, but as verbs over time (or rather, bounded by time): at a specific moment in the assembly line, call this particular method, at another moment, call that other method… Object oriented programming in the Simula tradition I would even go as far as to say is just best practices in structured/procedural programming taken to their logical extremes.
- jancsika 2y ago> Classes as a means of lifetime management Wrt plugin systems: at least as the class level, are classes really a means of lifetime management in practice? IIRC, audio plugin APIs follow the shell command pattern of memory management for loading new classes-- the user dynamically loads a library into a running instance of an application, and there it stays until the application exits. And even if plugin systems as implemented are actually unloading classes, the user is almost always just restarting the app to make sure it took. :) Edit: clarification
- recursivedoubts 2y agoAgree 100%: static typing (for code completion) + method/data bundling is the major win in OO, and it rarely gets talked about for whatever reason. It's unfortunate that inheritance became such a major focus of practical OO languages. Would love to see a composition-first OO language. Might have its own problems, but would at least be interesting.
- 1propionyl 2y agoGo, Rust, Zig, etc all support static typing and method/data bundling without any explicit language support for implementation inheritance (interface inheritance in general and especially when structural rather than nominal is not nearly as much of an issue and doesn't create strict tree hierarchies). Rust has support for variance and subtupint so perhaps it's not as pure of an example, but it's pretty heavily restricted. Zig's support for method/data bundling being used for "objects" isn't even first class so I wouldn't call it OO (object-oriented) so much as object-orientation-capable with less fuss than if one wanted to build their own objects system in C.
- j45 2y agoThe real world definitely isn't OO all the time. Maybe more functional and event based. The oscillation between the two as what's in favour is also humorous. The right thing for the right need for the present and near future, especially the newer the codebase, and the greater the need to learn, is often the way to consider pursuit.
- temporarely 2y ago> The real world definitely isn't Ironically, (ime/o!h;) it turns out this the "root of evil" plaguing abstraction: thinking that software architecture must map to "the real world".
- epgui 2y agoI think you have it backwards. Software exists in the real world, and is used to solve real world problem. In building software we inevitably invent or use abstractions to represent or effect real world things. Abstractions that make it easier to do this are good, abstractions that make it harder to do this are just getting in the way.
- temporarely 2y ago1 - (Application) System exist in the real world, not software. Software exists in machines. 2 - Computing is used to solve real world problem. 3 - "In building software we inevitably invent or use abstractions to represent or effect real world things." Here is the problem where we part company. 4 - Abstractions that inform computing systems are indeed useful. [edit+ps] self disclosure: I've reached 'architectural orbit' numerous times in my career. 30 years later, I am sharing a subtle point. Effective software models cutout attributes of real world elements of the problem domain. All attempt to "model the world" end in tears.
- epgui 2y agoThis reads like nonsense to me, so I can only assume the disagreement is semantic.
- pjc50 2y ago> dynamic dispatch makes it harder for newcomers to figure out the business logic by reading the code This is definitely a potential problem, but I note that you can also get into this mess without OO in any language that lets you put a (reference to) function in a variable. Or, god help you, operator overloading.
- bruce343434 2y agoOperator overloading isn't to blame. If I overload shift-left `<<` for a completely different concept such as "piping", that's my mistake. That's like writing a normal function or method and calling it `foo()` when it has nothing to do with the concept of fooing. That said, unless you are writing a math library or some container, there's not many good uses for operator overloading.
- pjc50 2y ago> If I overload shift-left `<<` for a completely different concept such as "piping", that's my mistake. Yours and C++'s.
- frogulis 2y agoI think the main difference between the two is, as someone reading and debugging the code, will probably eventually check even those methods that I assume I know roughly what they do. In contrast, I may not even think to check an overloaded operator unless I _already know_ that it's overloaded. Maybe a good analogous method would be an overloaded `.ToString()` in C# that has side effects or returns the full text of the Magna Carta or something.
- bunderbunder 2y agoCustom operators of any kind are definitely a problem for learners. I think people just fixate on overloading because that's the only kind of operator customization available in the most popular languages. The particular problem is that search engines tend to have terrible support for searching for arbitrary sequences of non-alphabetic characters.
- beryilma 2y agoBut, in a way, OO modeling and design was invented to solve the mess that "banging out" procedural code created in the first place. You have to model your business domain in software one way or another anyway. Why should it be bad to try to be more methodical about it using OO methods? We do it with relational databases all the time where tables are pretty similar to objects.
- nanomonkey 2y agoOO and Relational databases really don't mix well, so much that there are wikipedia articles on the subject [0]. ORMs create some of the worst SQL table layouts that I've ever seen, not to mention they generally cause tons of N+1 query problems. [0] https://en.wikipedia.org/wiki/Object%E2%80%93relational_impedance_mismatch https://en.wikipedia.org/wiki/Object%E2%80%93relational_impe...
- arendjr 2y agoI actually have nothing against objects and methods, but that’s a very limited subset of OO. I prefer to use algebraic data types for domain modeling, and giving them methods is totally fine too. But I do prefer them to be immutable in most cases, which is also quite counterintuitive from an OO perspective.
- fenomas 2y agoI'm not a big thinker on such things, but my general rule is that subtyping is okay only for implementation details. I.e. it's okay for ConsoleLogger to be a subtype of Logger, but PaidUser probably shouldn't be a subtype of User.
- green_dee 2y agoSo interfaces > modelling ConsoleLogger is a Logger because they share a method (log), PaidUser and User can have some common things, but I don't think it's only in the way it behaves, but also in the way you contact/use them
- anymouse123456 2y agoFWIW - OO has the same (or more) problems in GUI toolkits.