3

Steve yegge wrote an article called "Execution in the Kingdom of Nouns" back in 2006, 14 years later I still find the points he made valid. For example, "Action is what gives life its spice... (but) Object Oriented Programming puts the Nouns first and foremost ... nouns are things, and things are prized beyond all actions in the Kingdom of Java".

The example he used still resonates with me. Most of time when I write the a piece of codes to do a task, it normally consists of a serial of actions. Using his example of taking out the garbage to illustrate the the point,

  /*To take out the the garbage*/
  get the garbage bag from under the sink
  carry it out to the garage
  dump it in the garbage can
  wash my hands
  get back to my couch
  ...

what I need here are a serial of actions, not a serial of nouns like

A GarbageDisposalStrategy nouns, 
A GarbageDisposalDestinationLocator nouns for finding my way to the garage, 
A PostGarbageActionCallback nouns for putting me back on my couch.
...

I have seen too many codes with all kinds of manager classes, with public methods like run(), execute() or dothis().

And let me give a more realistic example to further illustrate my point. People always say choosing the right paradigm for the right problem. So let's take web development as an example. In web development we have lots of OOPs and frameworks, not just in java. But even since I use nodejs (express) to do web development I never use OOP, never miss it. Express's middleware is just a function chain.

So both OOP and procedural design work well for web development. But with express I feel far more easier, I spend more time in developing the "real" code instead of learning the frameworks and all the design and twist in the framework.

What is the "right" paradigm for web development?

What are the disadvantages of OOP, especially in java (in web development & in general)? Does OOP overemphasize the importance of noun and thus put action/verb in the less importance position ?

I also need to emphasize that my question is not to discuss/promote functional programming or to start a language war. I am fully aware that my question maybe seen as opinion-based or too broad. But the fact that 14 years later the problem is still here makes me ask this question.

---- update ----

One more vote and my post will be deleted. But please, the future readers, don't vote to delete it, it has been closed, why delete it? I do think it raises a valid concern, why delete it?

Although my question was closed (as I expected) I want to point out that there was a same question at stackoverflow (before I changed my question title), which was also closed https://stackoverflow.com/questions/2853316/disadvantage-of-oop

There are some good answers there so if you have interest take a look. An answer I quite agree is (maybe because many of my codes are transformative processing)

OOP works best with large-scale, multi-developer, multi-module projects. For "development in the small" - such as scripting or transformative processing, it can require a good deal of overhead without necessarily adding value.

...

transformative processing is quite amenable to the functional style of programming

PS, if you think Steve yegge's article is gibberish, you may check Joe Armstrong(father of erlang) article Why OO Sucks, much shorter, straight to the points and yet basically made the same arguments, like "Data structure and functions should not be bound together."

  • 2
    I think Alan Kay would strongly contest the notion of OO being about nouns - softwareengineering.stackexchange.com/questions/46592/… – Ben Cottrell Nov 18 at 15:05
  • My opinionated 2 cents: Note when people write procedural code, often it isn't written it as described in the "To take out the the garbage" example. Instead, it's written in terms of even smaller steps, in terms of concepts that are at a lower level of abstraction. E.g., the "get the garbage bag from under the sink" bit is written as some obscure-looking sequence of instructions. Many people don't wrap that into GetGarbageBag(sink), and it stays that way - with no explicit separation of concepts or control over unwanted accidental coupling, which happens as the code changes and grows. 1/3 – Filip Milovanović Nov 18 at 17:37
  • But even if they do, as the code grows further in scope and complexity, it often doesn't occur to people to do it again. They never make the TakeOutGarbage() function, even though they may leave the // take out the garbage comment above that sequence. So they never come to the step where they change it to TakeOutGarbage(then: () => GetBackToCouch()) because maybe they realized that this happens to be a better, cleaner design for their particular problem. Instead, it just gets more complicated and tangled. This is how you end up with 1000 line functions. 2/3 – Filip Milovanović Nov 18 at 17:39
  • What I'm talking about here are abstraction skills, modeling skills. So far this had nothing to do with OOP specifically, it's more fundamental than that. But my point is, if you consistently end up with 1000 line tangled functions without OOP, then you won't be magically writing nice, clean code using OOP. Furthermore, you won't even be able to begin to see what the pros and cons of OOP are compared to, say, functional programing, and when and how to use one vs the other, etc. 3/3 – Filip Milovanović Nov 18 at 17:39
  • All actions requires both tangible and intangible nouns to execute them. In the example of a get the garbage under the sink, you are missing a lot of steps that the single action requires which are being combined to perform this higher level action. (ex bend down, extend are arm, close fist, retract arm, stand up). Each of those actions have tangible nouns (ex. arms and legs) and are themselves combined into an intangible action (a strategy for getting the garbage from under the sink.) The actions being taken are the code, the nouns are how we organize the code. – yitzih Nov 18 at 22:09
12

One of the problems with OOP is not what OOP is, but how it is taught.

Alan Kay, who coined the term "Object-Oriented Programming" has made it very clear on multiple occasions that Messaging is the most important thing in OOP. He has even said that he regrets called it Object-Oriented and should have called it Message-oriented instead.

So, even from the very first days of OOP, the focus has been on the Interaction, not on the Thing.

However, the very first technique for object-oriented analysis being taught is "underline all the subjects, verbs, and objects in the use case; the subjects become classes, the verbs methods, and the objects fields."

Note how this methodology does not even focus on objects, it focuses on classes.

But even if we assume that this methodology is a good methodology, you can still end up with widely differing designs, depending on how you formulate the use case.

One of my favorite examples is banking. The BankAccount is one the most-widely used introductory examples in OOP. And "everybody knows" what a BankAccount is, right?

class BankAccount {
    private Money balance;

    void deposit(Money amount) {
        balance += amount;
    }

    bool withdraw(Money amount) {
        if (balance < amount) { return false; }
        balance -= amount;
        return true;
    }
}

Easy-peasy. Now, add the transfer method. Oh, wait, what object does it belong to? Does A transfer to B or does B transfer from A? And what about concurrency?

class BankAccount {
    Money balance;

    void deposit(Money amount) {
        balance += amount;
    }

    bool withdraw(Money amount) {
        if (balance < amount) { return false; }
        balance -= amount;
        return true;
    }

    bool transfer(Money amount, BankAccount target) {
        if (balance < amount) { return false; }
        withdraw(amount);
        target.deposit(amount);
        return true;
    }
}

"Everybody knows" that "balance" is data and "transfer" is an action. Right? RIGHT?

Well, turns out that's not how it works. In fact, it has never worked that way, all the way back to when bank transfers were first invented.

What happens when you make a transfer is that the clerk writes a transaction slip, and at the end of the business day, all the transaction slips for the account are tallied up, and this yields the new balance. Then, the transaction slips are sent to the receiving bank, where the same thing happens.

So, in the "real world" (which every OOP tutorial teaches us we are supposed to model), the transaction is actually data and the balance is actually an operation!

record Transaction(BankAccount source, BankAccount target, Money amount)

class BankAccount {
    Money balance() {
        // find all transaction slips which have `this` as either source or target
        // add all the amounts which have `this` as target
        // subtract all the amounts which have `this` as source
        return result;
    }

    void deposit(Money amount) {
        TransactionLog.append(new Transaction(CASH, this, amount));
    }

    void withdraw(Money amount) {
        TransactionLog.append(new Transaction(this, CASH, amount));
    }
}

Note that all of our concurrency problems go away: BankAccount is immutable, Transaction is immutable, we only need an "almost-immutable" append-only TransactionLog. We also get a full audit-trail for free, and can recover from partial data loss.

That is not actually surprising if you consider that this is how banking has been done since the times when moving transaction slips via horse courier between branches and banks was risky and may have taken days. This has exactly the same problems and properties as a distributed electronic banking system.

So, as you can see, we can flip the roles of nouns and verbs for the exact same problem just by approaching the problem differently.

Also, note how the complexity of the problem and the context requires having multiple independent concurrent actors, namely at least the two branches of the bank. That is what OOP is supposed to be: multiple independent actors collaborating by exchanging messages while keeping their own workings hidden from the rest of the world.

| improve this answer | |
  • Alan Kay also said that everything is the same (the "cells"). There is no "data" in OO, there are only objects. – Robert Bräutigam Nov 18 at 15:10
  • 1
    Using the example of "taking out the garbage", would you append to a TrashactionLog instead? – Duroth Nov 18 at 15:30
  • I know what you said, but your example didn't change the fact that noun is the king while verb is the second-class citizen if I may argue. – Qiulang Nov 19 at 2:18
  • You may also check this stackoverflow.com/questions/2853316/disadvantage-of-oop (I have updated my question even though it was closed) – Qiulang Nov 19 at 3:44
4

It's normal for people to think about a "series of actions" when thinking about a problem. It's easy, and anything and everything is under your complete control. Nothing wrong with that, it is just a way of thinking.

OO requires a completely different thinking though. Instead of command-and-control, you are actually encouraged to think of work as a cooperation among colleagues. It's not about "things", it is about living things. You give up control yourself in order to delegate tasks to other beings (i.e. objects).

To answer your question: The linked article is BS of course, or rather, it is a strawman. Sure, if you are doing OO very badly, plus you're overcomplicating everything, it will look pretty bad. Even if that applies to some frameworks or libraries, it's not OO at fault here, just people's wrong interpretation of it.

| improve this answer | |
  • 1
    It's been a while since I read anything from Steve Yegge but IIRC he had a strong functional slant. This was written before Java supported passing functions. I don't think that there's much serious debate about whether function passing is a good feature any more but at the time of this article it was somewhat of a religious battle. – JimmyJames Nov 18 at 17:30

Not the answer you're looking for? Browse other questions tagged or ask your own question.