63 comments

[ 3.1 ms ] story [ 67.9 ms ] thread
(comment deleted)
The author is missing maybe the following point: when there will be multiple objects that need to move, and some of the move methods will require state, then it will be nice to encapsulate the state within objects, rather than having messy global state and methods that access a global state... which can lead to coupling between methods, if not concurrency issues, and before you know it, you end up with hard to understand, non-maintainable, non-refactorable spaghetti code.
Regarding Dijkstra's quote: our brains are wired to model people with internal desires... sometimes it can lead to some errors, like animism, but if used correctly, it can be a powerful technique.

I've designed concurrent systems with many processes talking to each other. Each process has a name that describes a profession, owns certain parts of a shared database and transacts with other processes.

Sure that analogy can break down in the limits, but thinking like this allows me to get a much clearer mental picture of what's happening.

(comment deleted)
One obvious problem with that comparison - it is a toy example.

It is really not about anthropomorphizing objects, it is about where the state is kept and who can modify it how. And the right or at least the best choice heavily depends on the problem you are modeling. If you are primarily tracking the whereabouts of students it is probably a good choice that students keep track of that information and provide an interface to update it. If you are primarily interested in rooms and who is inside, it may be better to make the rooms responsible and provide an interface like classroom.enter(student).

Bad programmers write bad programs. It's not methodology. Good programmers have successfully written a lot of software in an OO design. That doesn't mean OO is the best solution for you, it just means that you can't judge a book by its cover, and in this industry, we're covered in bad programmers.
Disagree! If a programmer is good or bad is not a quality separate from how they actually develop programs! A good programmer is good because they choose appropriate tools and methodology etc.
That is not at the granularity of "OO vs. FP". Again, plenty of people have very successfully built projects with the OO methodology. That doesn't mean you have to. That doesn't mean it's what is best for you. But articles like this ignore fundamental, empirical proof: OO has worked. There will be hundreds, maybe thousands, of projects started this year in an OO methodology, and they will live or die not because the developers chose OO, but because of generally more basic issues of competency.

I interview developers for positions all the time. Out of every 10 I interview, one can't write a basic "Hello, world" program that actually compiles, in the languages they list in their resume, on their own computers. About 7 or 8 more can't even close a database connection or file handle correctly. I can go a year and meet one, maybe two developers I would trust to write code in any methodology, in any programming language. And they usually have jobs they like and don't want to leave.

Projects don't fail because someone chose OO. They fail because most people claiming to be developers suck.

> articles like this ignore fundamental, empirical proof: OO has worked. There will be hundreds, maybe thousands, of projects started this year in an OO methodology, and they will live or die not because the developers chose OO, but because of generally more basic issues of competency.

If projects live or die based on competency, not methodology, then how is the existence of so many projects proof that "OO has worked", rather than proof that "Software Engineering is prone to bandwagons and hype"?

Agree that experience shows that it is possible to build successful projects in OO. But nobody have suggested otherwise. It might still be that some other paradigm might be better, e.g. the successful project might have been done faster and cheaper using a different method.

The existence of crappy programmers definitely does not suggest that all methodologies are equally good.

Very much agreed, the point you're making is exactly why I hate languages that try to hide the fact that programming is difficult, to make the life of the developer easy. This almost inevitably encourages bad programming practices, and does not do anything to improve code quality produced by incapable developers. It's why I dislike Java so much and prefer C++, even though both have their strong and weak points, and both can be used to create great software.

That said, I've stopped taking 'OO is bad' articles seriously long ago. Over 15 years of professional software development have sufficiently proven for me that there are many problems that fit the OO model perfectly, and would not benefit in any way from switching paradigms. Just like some (but decidedly less) other problems are a perfect fit for functional programming or procedural programming. There is no silver bullet in programming, what works best is entirely dictated by the problem, and problems come in infinite varieties.

I was disappointed by this article in the end. I was ready for a good old fashioned OOP bash, supported by strong opinions and examples. We should always remain open to new (or old, in this case!) patterns. Instead we get a "tie" given a very simple (not real world) example.

In the end I'm left with the same conclusion. Given that there is no obvious performance gain from a procedural approach, I would opt for a design pattern that is friendlier to the programmer (the human being). It's helpful to model things this way as an organizing approach. And there are obvious benefits to maintaining state within their respective concerns.

It isn't to say OOP is the only and best answer. It very much depends on the program, but I was hoping for a more obvious win on the procedural side here.

I was also disappointed by the atricle's end: Pretty much only the Dijksta quote was worth reading. The title promised to backup the claim with a real-world experience of OOP, but alas, it did not deliver such.

OOP is better where you code more readably(in comparison with procedural) and where it makes you enjoy coding more. The conditions for when it does that differ from persons to person and from project to project.

I personally like OOP because it helps me focus on different abstraction levels at the same time, and it helps me stay in the flow.

(comment deleted)
I don't think procedural programming itself makes code unreadable. For example, take a look at the redis source code. It's clean and approachable.
I do not find procedural code unreadable, nor is that what I meant to say. Rather the contrary: I said that OOP is only better if the same problem solved in OOP is more readable, which holds only true for a subset of problems.

Regarding the redis source code: Beautiful, truly. I wish more code was that clearly and extensively documented.

I think the procedural option is better. It is just so much less code.
(comment deleted)
It does until it doesn't. Let's say you only want to move the bad students to the principal. Then you want to model pop quizzes. Students who score 1/5 on three or more per month go to the principal. Or call their parents, whatever.

After a while you realize that you're doing all this stuff to 'bad' students. This is where you really start to want some way to organize all the stuff you're doing to these bad students, as all the code you have dealing with them is sprinkled liberally through the codebase in conditionals in your procedures.

You'll start pulling out logic and things will start breaking. What you thought was less code is just crazy to manage.

The Gilded Rose kata illustrates the dangers of procedural code excellently.

http://craftsmanship.sv.cmu.edu/exercises/gilded-rose-kata

Sandi Metz has an excellent discussion on using OOP to improve the design of a codebase.

http://www.confreaks.com/videos/3358-railsconf-all-the-littl...

It is less code because it doesn't use encapsulation. So is encapsulation a benefit or just needless overhead? Depends on the size of the program.
still i would like to see a concrete example where OOP is better. I thought that OOP had advantages in larger projects with many kinds of data where it helped organize the code to make it more readable and editable. At that point you need to be careful how you use it to make it manageable. Not sure how small an example would could be before it started to show some benefits.
The encapsulation that guarantees invariants is the greatest benefit. This can be Done in another way by immutable structures and Functional programming. This way is in many ways better than OO but both are vastly superior to having publicly mutable structures modified by procedures.

Semantic organization where methods are defined near the data (the recepie is on the flour package) is a benefit for sure, but it's just a preference.

This part of the article really says it all:

> There is just one little snag… The limits of analogies …When pushed too far, analogies break down.

It is really hard to decide on the best way to model, since it doesn't resemble any real-world programming problem.

But OO culture has an unfortunate tradition of using bad examples by using physical objects as analogies for objects in code. Cars, fruits, students, teachers, whatever. Problem is, objects in code rarely correspond to physical objects. In the cases where physical objects are represented, it is most often in the form of database entities, which are typically treated like data-objects, which makes the discussion in the example moot.

Better examples? Behaviors. States. Event processing machinery. Objects to help support those things.

Containers are also used to demonstrate OO, but they're so abstract only a compiler geek could love them.

In my experience as a technical instructor -- who frequently has to introduce concepts like the HTML DOM to students who have a hard enough time with markup -- overly simplified metaphors can get over the "can't learn, too hard!" barrier that adults tend to put up when they're expected to learn something new. FWIW, I use the car metaphor, and as a class, we all break it down into simplified properties, methods and events.
You hit the nail on the head. Objects in OO shouldn't be a projection of the problem domain, they're a way to structure the program (there's some overlap, of course).

Many people seem to get this wrong, probably in part due to introductory examples doing it wrong.

I suppose you disagree with Eric Evans method of Domain Driven Design (DDD - http://domainlanguage.com/)

Don't people who practice DDD, including Martin Fowler, commonly talk about the benefits of some of it's concepts, while modeling the Domain using Aggregrate Roots, Bounded Contexts, etc?

Martin Folwer talks about several approaches for handling domain logic. Transaction Script, Domain Model, Table Module, and Service Logic. He explains the trade offs of each on the Patterns of Enterprise Application Architecture book.
Since then he has also written a lot more as well, for example http://martinfowler.com/tags/domain%20driven%20design.html .

While less a direct connection, folks who use DDD a lot also find CQRS (command query responsibility separation) a natural fit and are often seen being used together.

Yeah, that makes sense. It simplifies both.
Those examples are used for teaching because they are interesting for novices. In a real project, you use your objects that are useful for organizing your code. Modules, layers, gateways to external systems, etc.
This confuses OOP/procedural semantics with low-level "CPU" work. The argument seems to be that the programming model of a language does not always expose the efficiency of the underlying implementation. And this is also true for "anthropomorphic" models.
Like many people I went through an "objectify all the things!" phase, but now I find myself moving more and more to stateless service layers, which ends up looking like old-fashioned procedural code coated with a sugary OOP shell.

Encapsulation and inheritance and stateful objects have their place, but the "object" metaphor can really lead down the wrong path when taken too literally (as it is in practically every course that starts with "animal" or "shape" or "car" examples).

If I don't explicitly need "state" (user-data in models or GUI-state in view-models) I leave it out.

Most of the time I use classes and their objects as a stateless bag of related methods. Like namespaces...

IMHO classes are a "jack of all trades, master of none". They're sort of like namespaces, a bit like modules, kind of like closures, somewhat like types, almost like first-class functions, etc.

On a somewhat related note, http://www.newspeaklanguage.org uses classes for all kinds of things, including namespaces.

lol, yes.

But I have to admit, the dynamic properties of objects make them much more versatile than namespaces or modules.

If I would use them only as namespaces, by defining every of my (stateless) methods static, they would work exactly as a namespace. But when they're bound to an object instead, I can switch out implementation details easily when needed. So I would consider classes and their objects to be a more powerful version of namespaces.

> Like many people I went through an "objectify all the things!" phase, but now I find myself moving more and more to stateless service layers,

These are not mutually exclusive.

Could not agree more.

I've heard of interviewers who say to candidates: "I have a bookshelf. Design me an OO interface." They want the candidate to create objects for Shelf, Book, etc. without knowing anything at all about what the software system is supposed to do! This is so backwards IMO that I cringe just to tell this story.

I was asked to whiteboard the object model of this exact question.
The intent of that type of question is to see what questions the candidate asks in order to elucidate an appropriate design.

That being said, I can easily imagine it being misused by bad interviewers.

Yup.

<rant> YMMV

Early in the OOP fad phase, the suggestion that OOP had any very close connection with real world objects and the idea described in the OP as anthropomorphism sent me into nearly a rage of indignation -- as if I was being force fed conceptual sewage.

E.g., consider plants, billiard balls, cars, bottles in a cupboard, etc. with each represented by a software object (that is, an instance of some class) and then want to program some real world situation for those real world, physical objects, say, the first shot in a game of billiards where the balls bounce off each other and the rails and fall into pockets, where planets affect each other via gravity or collide, where cars move as in traffic, etc.; then, we ask, do the programming constructs of OOP really, naturally, automatically, or even seriously help handling the billiard ball collisions, the gravity, the traffic jams? My view was -- not really, at best not much.

Eventually I just decided to regard OOP as a glass half full and like what was there that I could like and f'get about the rest; then I regarded an instance of a class as much like what the OP calls a record or, more accurately, like a structure in PL/I.

Note: PL/I structures have a really nice advantage because all the addressing is just array addressing -- super nice, that is, simple and fast, that is, typically there is little or no need for the compiled code to follow pointers to get to variables in the structure.

Then the definition of the class was much like a based structure in PL/I where could allocate as many instances as desired. Then for the OOP methods, in PL/I just have some entry variables in the structure. The rest of OOP looked like no more than syntactic convenience (sugar). Actually, for OOP inheritance, PL/I had key word LIKE where could have a structure A and then define a structure B and for part of B say it was just like structure A.

For OOP inheritance and polymorphism, I was not impressed: So far, in my own code, I've never used inheritance if only because there will be source code dependencies likely a long way away in the code base -- e.g., might be inheriting from some class have never seen, which sounds like programming partly in the dark and risky, that is, error prone. For polymorphism, I've used it a few times -- okay, I did it with interfaces which are essentially the same as passing an entry variable in old Fortran. For encapsulation, sure, I get some of that when I use some of the classes in the Microsoft .NET Framework; if I can trust what Microsoft did, and really I have little choice, then okay. I have written a few classes where there is some encapsulation -- push the low level details out of sight where I don't have to work with them or risk using them wrong and making a mistake. E.g., have a class that reads a file and has a method that on each call returns the next token in the file -- not a biggie.

Two final points:

(1) Simplicity.

Mostly just keep everything as simple as possible but not simpler. If something is at all complicated, then write some good documentation to explain it and show that, still, actually, it really is simple. With things so simple, a lot of the tricky stuff in this and that programming language mostly don't much need.

E.g., a closure sounds a lot like passing to a function A an entry variable as an argument to a function B and where function B uses some syntactically nested scope of names to manipulate variables it has access to merely via scope of names and where the function A does not. I did that a few times in PL/I; it's tricky coding, and I'm not thrilled with it.

(2) Libraries.

The code I write is mostly just mortar or glue to hold together uses of functions and methods in classes from Microsoft, etc.

In my project, at time...

I read a Java textbook that started with something like "OO allows you to model things like they are in reality. A dog has a tail, and it can be wagging or not. A dog has a name..."

But dogs don't 'have names' in the OO sense. Humans have names for dogs. We can give a dog two names and it doesn't matter whether other dogs have two names or not. We can have a dog with no name, yet we can still call it by something as though it were a name. We can talk about the name of a dog that doesn't even exist.

OO is a valuable methodology, but you shouldn't have to lie to yourself to see that. It's a convenient way to bundle certain concepts together, and many problems do not require -- or are actively hindered -- by that bundling.

Well names are a bit of a bad example. Entire fields of study were spawned from that example [1]. A better example might be a credit card, which always has a number and a cardholder. Things get interesting when you might formalize:

* Expiration (do all credit cards expire? Is expiration necessarily a date, or is it a predicate?) * Cardholder - referent might be another entity in your system * Is the card number encrypted? How do you represent encryption?

[1]: https://en.wikipedia.org/wiki/On_Denoting

These kind of issues lead to the development of aspect-oriented programming, which is an attempt to better match our intuition about how things in reality behave in a compositional manner.
Using the article's example, maybe if you break the abstraction of the iterator, you realize that moving students to classrooms might just be a single pointer assignment, which can be done in a few instructions. In other words, maybe the classes blind you to the fact that the students don't need to be iterated.

I feel like this is one of my bigger gripes with OOP code bases: overemphasis on abstraction sometimes makes simple and efficient solutions harder to come by.

Completely disagree with the Dijkstra quote. Mentally modelling command flow as a 'person' makes total sense, as long as you keep in mind the abilities/limitations of the 'person' you're talking about.

That said, I agree that OOP is anthropomorphism gone crazy.

The article resonates with me.

I’ve spent quite a few years coaching and dealing with developers with a heavy electronics background work in OO/C++ environments and I came to the conclusion that they would be more comfortable and competent in C. All smart people but the bells and whistles of C++ AND OOP just was confusing.

I’m surprised at some comments here claiming that OO is ‘friendlier to the programmer’, I would put money on the average developer being able to work their way around even the Linux kernel quicker than a comparably sized C++ code base with all it’s OO goodness.

What OOP was trying to solve back in the day was and still is a real problem but it annoys me how many additional problems ‘full blown’ OOP introduces.

Is this a joke or something? The arguments simply don't hold water. OOP will make the program run faster? Was running faster than whatever is a promise of OOP? Walking each student while the others wait in the main hall would take forever? So we are talking about parallelism with the actor model. How would procedural help that?

"[OOP] just organized in a more systematic way." Managing complexity and abstraction is a main function of programming. How is having a simple, consistent, systematic way to organize complexity not an advantage?

"It is not simpler. Just organised in a more systematic way."

This is the kicker. In most large projects(100k-million+ loc) the largest issue is complexity. Object oriented programming is just systematic way to organize that complexity.

The OP says that "In production code, I would split it in several files as appropriate. Or not. It doesn't really matter. What does matter is that we can easily find those procedures whenever we want to inspect or modify them."

It 100% does matter, and having all procedures that operate on and change the state of an object in the same file is super helpful. Being able to make guarantees that certain state cannot be changes outside of the organization unit of the class(encapsulation) is super helpful. Being able to abstract over certain related but non identical functions without having to resort to switch statements is super helpful.(polymorphism) And the ability to reuse code when different pieces of data share some identical features and we want to abstract over a portion of those features is useful(inheritance).

OOP doesn't give you any abilities you didn't have before, and you can write great readable structured procedural code. But it does give you more tools in your tool box that when used correctly can help structure your code in a way that limits the burden of the software's complexity.

Agreed. A main selling point of OOP is that it makes it easier to reason about the code by providing a coherent hierarchy. It's certainly possible to create a custom system of organization for procedural code, but it will by definition be ad hoc and harder for new team members to get up to speed with.
> having all procedures that operate on and change the state of an object in the same file is super helpful.

How many OOP programs do you know that have achieved this? None that I know. Perhaps utility libraries can get close, but no software actually solving domain-specific problems. Objects don't live on their own, in a typical OOP program there are bits of code all over the place that operate on your data objects. Finding all the ways that a personel record is modified can be a tricky problem. More so because the object is likely to be a bastardized combination of personel data and software engineering level-of-abstraction (see below).

> Being able to make guarantees that certain state cannot be changes outside of the organization unit of the class(encapsulation) is super helpful

Agreed, but woefully limited. The idea that a class should be the unit of encapsulation leads to all kinds of horrible programming idioms, leaked abstractions and interface complexities. A better solution would be to erect encapsulation barriers explicitly, rather than tying them to an unrelated domain-modelling semantic.

> Being able to abstract over certain related but non identical functions without having to resort to switch statements is super helpful.(polymorphism)

Or just polymorphic dispatch, which if you're going that way, you can add multiple dispatch and get much more power, security and expressivity.

> And the ability to reuse code when different pieces of data share some identical features and we want to abstract over a portion of those features is useful(inheritance).

Except that again, OOP encourages programmers to think of code reuse in terms of an unrelated domain-concept, which leads to class design that is motivated by functional needs, rather than domain needs. Which is again a bane of real OOP systems.

> OOP doesn't give you any abilities you didn't have before, and you can write great readable structured procedural code.

Agreed. You can write OO procedural code. I've written quite a lot of OO C, for example.

> But it does give you more tools in your tool box that when used correctly can help structure your code in a way that limits the burden of the software's complexity.

I'm skeptical that 'when used correctly' is anything but a no-true-scotsman fallacy. In practice, the way OOP pushes together concerns of domain, semantics and syntax seems to encourage code that lacks the kind of encapsulation, reuse and separability that OOP-devotees claim is the raison d'etre of their paradigm.

I bought OOP in a big way through the 90s and into the early 2000s. I'm sorry to say I think the emperor has very few clothes. The realities of the big software systems you cite seem to be very different from the clean simple benefits demonstrated on toy problems in CS classes.

Three issues I've hit time and time again, in the millions of lines of OOP I've written and maintained: one is the expression problem, a second is the fragile base class, and a third is the metaclass problem (where the domain requires three levels of modelling, but the language provides two, or provides metaclasses with semantics that 'break' the principles of OOP you mention).

> Objects don't live on their own, in a typical OOP program there are bits of code all over the place that operate on your data objects. Finding all the ways that a personel record is modified can be a tricky problem.

Searching for all the code that touch an Employee record class is much easier than searching for all the code that touch a generic hashmap that supposes to contain the employee data.

This a property of static typing, not object oriented design. Take for example Typed Clojure, where you could define an Employee as a hashmap with a set of static constraints which can then be analyzed for, without having to invoke any of its proper OO constructs.
Why on earth would you use an untyped generic hashmap for employee record data? What kind of language do you think forces you into that kind of architectural decision?

Certainly no language I have or would develop an MIS in, regardless of paradigm.

The biggest problem I see with this article is the author is comparing Simula style OOP (Prevalent in C++, Java, C#, etc.) with procedural style programming and concludes anthropomorphism is at fault.

When your objects act more like very lightweight processes ala Smalltalk or Erlang model that communicate with each other via messaging, OOP becomes a lot more than a "coat of syntax sugar over the procedural cake" and anthropomorphism sudden works very well. If you see objects as data structures with methods rather than isolated processes with message based interfaces (think actor model), it's not all that surprising anthropomorphisms don't add much value. However, when your conceptual model of objects implies each object is a concurrent and isolated process, anthropomorphisms make sense. I sometimes even give them names and imagine them as employees in an organization. Asynchronous communications can be conceptualized as inboxes and outboxes of messages and synchronous communications can be thought of one employee getting into a queue himself to personally deliver the message.

Sometimes metaphors translate surprisingly when you become a stickler for making sure all aspects of a metaphor are accounted.

According to Alan Kay:

http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...

---

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I'm not aware of them.

---

I think over the years OO just ended up meaning "whatever C++, Java and C#" implemented. But you are right, if you go back to its original design Erlang is probably more OO than any of those languages. I believe this was Joe Armstrong's tongue-in-cheek observation a while back as well.

Maybe concede the term OOP to Java, C++, et. al. and call message passing among processes service-oriented programming or something.
...and give up the opportunity to remind programmers their OOP is the inferior OOP? :)
Not really a great example, really a straw man argument because the code is so shallow. It's really about having relevant code in the relevant place. So yes the student object could have that code placed in it's class. That would be truly effective if you had, say, two kinds of students. Like one in a wheelchair and one that can walk. They'd both implement the function to move to the classroom, but internally one would walk() and the other would roll(). That's polymorphism. In the procedural case you'd have to check if(student.inWheelChair == YES) and it would get complex.
The article isn't wrong, per se, but it offers a terrible strawman example. It is an example of OO done wrong, not a criticism of OO.

The example offers a flawed data model. Each student is in a classroom, but it doesn't make sense to model the location as an attribute of the student -- unless it is actually a coordinate position. If it's a symbolic location (a classroom), it is much more logical to treat the classroom as a container; therefore it is the responsibility of the containers to move stuff around.

OO tends to make much more sense once you analyze where the encapsulation should be.

I find myself not wanting to use or focus on objects at all. I am more interested in message passing and protocols. Seem like a big blind spot.