Help

Well, this post really brought out the crazies. Folks told me that I don't know what an object is, called me ignorant twice, quoted Alan Kay at me, and accused me of being a C programmer. :-)

(What is it about the Internet that makes it okay to call someone ignorant just because you happen to disagree with them?)

Best I can tell, what infuriated these (well-informed, intelligent, passionate) people was the following statement:

Objects are stateful, and one of the main purposes of the methods of an object is to export that state (data) to the world.

A typical objection was:

The fundamental tenet of Object Orientation is that the state of an object is not exported out through the public behavioral API.

The fundamental tenet. Got that? ;-)

Okay, so let's take this idea seriously, and see what kind of impact it would have upon the design of our system. Let's start with Order. According to these guys, this is the perfect object:

class Order {
        private Status status;
        private List<OrderLine> orderLines;
        private Customer customer;
}

This class obeys the fundamental tenet. It exposes no state to its clients. Unfortunately, it's also totally useless for anything except looking at and admiring its pure, beautiful objectyness. If we want to actually use it for something, we're going to need to be able to add new OrderLines.

class Order {
        ...
        private List<OrderLine> orderLines;
        ...
        void addOrderLine(OrderLine line) {
                orderLines.add(line);
        }
}

Does this violate the fundamental tenet? I'm not sure. It's not clear to me whether a mutator method exports the state of an object. I would say it does, but we've already established that I don't know what an object is.

Unfortunately, we're not quite done. We can only add new OrderLines if the Order is in a certain state. Let's fix this:

class Order {
        private Status status;
        private List<OrderLine> orderLines;
        ...
        void addOrderLine(OrderLine line) {
                if ( status.isSubmitted() ) {
                        throw new IllegalStateException();
                }
                orderLines.add(line);
        }
}

Nice! We obeyed the fundamental tenet!

But ... when we display an order to our user we really need to know in advance whether its okay to add new lines. It's not okay to let them find out when the addOrderLine() method blows up!

class Order {
        private Status status;
        private List<OrderLine> orderLines;
        ...
        boolean canAddNewOrderLines() {
                return !status.isSubmitted();
        }
}

Oooop! Wrong! We violated the fundamental tenet! We exposed the state of the object to its clients! What can we do to fix this? Well, we could try to make the object responsible for rendering itself to the user interface:

class Order {
        private Status status;
        private List<OrderLine> orderLines;
        ...
        public void render(Panel panel) {
                ...
                if ( !status.isSubmitted() ) {
                        panel.addButton( .... );
                }
        }
}

But ... doesn't this approach just expose the state of another object (the user interface for Order) to the Order class? Worse, it creates a dependency from the domain model to the user interface, a deep error in terms of architecture. But this is just the beginning of our problems! We really need to be able display the total price of the order to our users:

class Order {
        ...
        private List<OrderLine> orderLines;
        public Amount getTotal() {
               Amount amount = ZERO;
               for (OrderLine ol: orderLines)
                       amount.add( ol.getAmount() );
               }
               return amount;
        }
}

This method also exposes the state of the object; and so it also violates the fundamental tenet.

And, sometimes, the user interface needs to display information about what Customer an Order belongs to.

class Order {
        ...
        private Customer customer;
        
        public Customer getCustomer() {
                return customer;
        }
}

Clearly, this one of those evil getter methods we've heard about; it exports the internal state of Order directly to the world!

So, where do we go from here? How can we design our system so that we obey the fundamental tenet of Object Orientation? Well, one approach we could take is that we could just accept that this fundamental tenet is not so fundamental after all! Perhaps it is more of a recommendation, a guideline that we take into account along with many other conflicting constraints that apply when we design software. Some of these constraints are general principles of good design. Some are architectural practices. Some are special restrictions of the programming environment we are working in. Some are simply concessions to practicality!

Another possibility is that we've misunderstood this tenet. Perhaps what it is really saying is not that objects never expose their state, but rather that they expose it in a controlled fashion, via intermediating methods that abstract the internal data structure and control access to it.

Well, it's not for me to say which of these interpretations is the correct one, since, as we've already established, I don't know what an object is. Besides, this is not really what I want to write about today. The topic I really want to talk about is religion.

The folks who got upset over this issue displayed the classic symptoms of a religious mindset:

  • Appeal to authority: In the Bible, it says..., Alan Kay writes..., What would Jesus do?
  • Argument from overly broad principle: The fundamental tenet..., The Golden Rule...
  • Intolerance of dissenting opinion: Ignorant, Heathen, Infidel
  • Application of principle, without concern for consequence, and without sufficient understanding of the justification and motivation underlying the principle.

Worst of all, religions set up absurd laws that no adherant of the religion can possibly obey (do not covet thy neighbours wife, getter methods are evil), and then demand shame of those that breach the rule. On the other hand, the absurd law is taken, by adherants, as a license for denunciation of free-thinkers: those of us who believe it's perfectly okay to check out the bangin' ass on the chick next door, even as we're being faithful to our gorgeous wives and girlfriends. And those of us who think a getter method is a perfectly natural construct, the simplest and most natural solution to many problems. The great thing about denouncing free-thinkers is that the religious person gets to characterize their own opinions as the Word of God (or Alan Kay).

In general, the religious approach is very unhelpful in the field of technology. It blinds us to innovative new ideas and novel ways of viewing a problem. By contrast, the inquiring mindset is characterized by:

  • A tendency to argue from consequence: If we followed this approach....
  • Comfort with cost/benefit analysis: On balance, I think the advantages of this approach outweigh the disadvantages....
  • A willingness to search for the limits of applicability of general principles.
  • An openness to other paradigms and opposing points of view.

And so I'm back where I started: the ObjectMentor article. Why did I characterize this post as silly? Because it attempted to justify a new, unnecessary, architectural layer, without a single attempt at argument from consequence. Without even asking what the consequences of this horrible architecture would be! The ObjectMentor was in full religious mode, arguing from principle, without concern for practicality. And, as is often the case when we argue from principle alone, the ObjectMentor managed to forget some other principles along the way. More important principles. Principles like:

  • Simplicity
  • Don't Repeat Yourself
  • Ya Ain't Gunna Need It

The introduction of an extra layer would violate all these principles. But I suppose religions have always been big on unnecessary complexity and self-repetition. And religion is something that a person with a curious mind and self-confidence in his (her) own judgment and insight truly Ain't Gunna Need (in technology, or life).

29 comments:
 
12. Nov 2007, 17:18 CET | Link

Hmm... the inclusion of or life in the last statement makes it sound as Just Another Tenet From Another Religion.

:-)

ReplyQuote
 
12. Nov 2007, 19:46 CET | Link

Tell me Gavin, i guess you feel often very lonesome, to be part of the Hibernate Developing ( Object Relational Mapping Tool) without knowing what an Object is, don't ya?

regards, rené

 
12. Nov 2007, 20:09 CET | Link
Magnus Heino

The bad thing about

class Order {
        ...
        private List<OrderLine> orderLines;
        ...
        void addOrderLine(OrderLine line) {
                orderLines.add(line);
        }
}

is that it exposes OrderLine as something thats in used in the domain, and that it's stored in a private List in Order.

What if OrderLine is changed after it's added to the order? This is what I mean when I talk about exporting and exposing internal state, the side effects. Not if there are actual getters and setters.

A better approach would be (and this is what a rich domain model is to me) would be something like:

class Order {
        ...
        private List<OrderLine> orderLines;
        ...
        void orderProduct(Product product, int numberOfProducts) {
                orderLines.add(new OrderLine(Product, numberOfProducts);
        }
}

I see some kind of pattern in the latest post here, What methods belong on an entity? and Repository Pattern vs. Transparent Persistence. Sure, this code is probably ok, since you know that you should not change the OrderLine after it's been added to the Order. But the purpose of rich domain models, DDD aggregate roots etc is to make that clear in the design too, to communicate it using well defined patterns.

To me, this is a bit C-ish as you say in the topic ;-). It may work for you, but I find it very reasonable that people have other views on this.

 
12. Nov 2007, 21:17 CET | Link
Xavier

another advantage I see in using order.orderProduct(product, quantity) over order.addOrderLine(orderLine) is that it's easier and safer to maintain bidirectional relationships /if needed/.

void orderProduct(Product product, int quantity) {
    orderLines.add(new OrderLine(this, product, quantity);
}

is better than

void addOrderLine(OrderLine orderLine) {
    orderLine.setOrder(this);
    orderLines.add(orderLine);
}

because you are guaranteed to have a consistent OrderLine in one shot and not one with some missing properties (order).

Moreover, the user doesn't have to know how to instantiate an OrderLine object (in those dependency injection days, it seems the less we use the new keyword, the better it is ;-))

 
12. Nov 2007, 21:27 CET | Link
Ivan

Magnus, I don't understand the whole point of this. Why is it bad to mention OrderLine in the Order's interface, and how does the fact that we have the addOrderLine() method expose the list inside the Order? Why can we mention Product in Order's interface but not OrderLine?

 
12. Nov 2007, 21:30 CET | Link

Looks like java fanatics

Ruby has the nicest practical OOP model Only for performance reason would I choose another language (that fits into an OOP thinking, I believe OOP thinking wont bring you far in the haskell-like worlds)

 
12. Nov 2007, 21:32 CET | Link

Hi,

I almost fully agree with what you wrote. Beeing more than sceptic about OOP and an atheist myself, that was not really a surprise.

My only objection is that you are confusing two very different things: religion and superstition.

Superstition is made of those thing you believe in but don't understand and then you suffer from it. Religion should be made of the opposite: things you believe in because you do understand the benefit they yield.

Unfortunately, religions and superstitions are often mixed together, in various proportions depending on the context they were invented in.

Some faiths invented in the context of a backward cultures are more superstitious than others, sometimes up to a point where there is nothing in those faiths but superstition.

Likewise, some programming languages and paradigms specifically designed for below-the-average programmers tend to foster a moronic mindset.

 
12. Nov 2007, 21:40 CET | Link

Magnus, Xavier: nice job totally missing the point. I don't care if it's orderProduct(Product) or addOrderLine(OrderLine ol), it is /still/ mutating the state of Order.

And, by the way, the reason why you don't usually do things this way is because some entities have many attributes, and code like this smells:

class Person {
    void addAddress(String street, String city, State state, Zip postcode, Country country) { ... }
}

Long method argument lists should be refactored and represented as an object. And hey, guess what, we already have just the perfect object for the job: Address.

 
12. Nov 2007, 21:47 CET | Link
Ivan

Xavier: addOrderLine(OrderLine) doesn't mean you have to use new to instantiate the OrderLine instance. You can get an instance of it the same way you got the Order itself.

 
12. Nov 2007, 21:59 CET | Link
Dennis

The Alan Kay quote: OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.

I wonder if your critics are working in languages that have extreme late-binding. Java sure doesn't. Arguably it doesn't really have messaging either. If they want to use Alan Kay's definition, they probably need to admit they aren't doing OOP at all.

If they're Ruby programmers, they might have a leg to stand on.

Anyway, good post, simplicity and pragmatism beat complexity and theory any day.

 
12. Nov 2007, 22:06 CET | Link
Rob

Gavin, excellent post. I think a lot of the religion comes from a human tendency to try to make sense of the world--or technology or software development--by boiling things down to a simple set of rules that are easy to quote and were written by someone smarter than us. It's less work, frankly, than applying critical thought to new problems. That's okay, though: When the Singularity comes, the machines will rise and put us all out of our misery. ;-)

 
12. Nov 2007, 22:13 CET | Link
Xavier

Let's open the debate, even if I think if it should belong to the other thread 'what methods belong on an entity'...

Is using the Address entity really a good choice? What if I want to attach addresses to People and Orders entities as well? Will I need two different and incompatible address classes? One having a link to Person and the other to Order?

I would personaly make Address a value object persisted with a CompositeUserType (or embedded) and have a PersonAddress like this:

class PersonAddress {
    private Person person;
    private Address address;
    PersonAddress(Person person, Address address) { ... }
}
class Person {
    void addAddress(Address address) {
        addresses.add(new PersonAddress(this, address));
    }
}

By doing this, you also gain the ability to retrieve an address from a Person and put it directly into an Order. You can also add some properties on PersonAddress like a validity time interval (which is not needed for OrderAddress).

After all, I think it is a matter of taste... If you have a better solution, I will gladly change the way I do things right now. I'm really open to suggestions, especially from people who have invested so much time in developping a framework like hibernate.

 
12. Nov 2007, 22:18 CET | Link
Dennis

(btw to see what I mean about Java not really having messaging, google for higher order messaging and ask if you could do anything remotely like that in Java)

 
12. Nov 2007, 23:13 CET | Link

Gavin, it's pretty ironic (and sad) that you get on people for wrongly calling you ignorant, yet then go completely out of your way to actually prove your own ignorance and intolerance with that last sentence in your post. For example, many famously curious and brilliant people were and are Christians, with the Bible's truths complimenting and even driving their research. Fact.

 
12. Nov 2007, 23:34 CET | Link
Xavier

Ivan: what makes you so sure you'll have to add that orderLine to the order? What if there's already an orderLine with that product? In that case you could just change the orderLine.quantity property? So if you're not gonna use that orderLine, why create it in the first place? You could let the order decide if it should create a new orderLine or modify a previous one (let the order manage its own state).

By the way, I've nothing against a getOrderLines() method on order, that's part of the services an order can do. What would be the point of a TemperatureSensor without a getTemperature() method unless you could register some TemperatureChangeListener on the sensor... but the observer pattern is viable only if there's a limited set of properties and useful if you have to react to changes.

I think one of the great advantages of hibernate is that it does not force you to do things a particular way, it is flexible enough to let you choose your programming style (be it DDD or whatever).

 
12. Nov 2007, 23:36 CET | Link

But besides that unfortunate sentence (and a few other blanket statements about religions), the rest of the article was good and well-thought :)

 
12. Nov 2007, 23:47 CET | Link
Oleg Iavorskyi

Terrific post, Gavin! in.relation blogs are hot and interesting place these days :)

I'd like to add that religion itself isn't bad thing, promotion of only one right religion is.

 
13. Nov 2007, 00:58 CET | Link
Bob

Hehe, I agree. This kind of stupid formalism Java programmers and alike tend to throw around as words of wisdom is just a good measurement of their insecurity. The lets-deploy-this-rule-into-absurdity programmer only get that far since most of his time is spent updating overly complex generic abstract interfaces that does nothing. By cutting out all these over engineered crap you can cut your development time enormously. You don't have to cut corners or anything, just code what you need nothing else and see how much time you save for real work. When you get to the point that you actually need an abstract object factory interface listener (which I hardly believe anyone ever does) you create one. Not sooner. It's very tempting for the not so brilliant programmer to show off his 'skills' by implementing just that. Sounds cool, does exactly nothing you need and adds a lot of headaches for the next guy.

Some guidelines:

1. Code what you need, nothing else.

2. Good code is easy to get rid of (making refactoring possible)

3. You cannot foresee the future, don't code stuff that you don't need at the moment.

4. Avoid inheritance like the plague. Before you use it, ask yourself, is this thing X really an Y? Or does it just need an Y to function? The latter is true 99% of the time.

5. Use interfaces if you need polymorphism.

 
13. Nov 2007, 01:01 CET | Link
For example, many famously curious and brilliant people were and are Christians, with the Bible's truths complimenting and even driving their research. Fact.

Of course this is true. Most of the great advances that lifted humanity out of ignorance, brutality and poverty were the product of religious individuals (but to be fair, let's not forget that organized religion fought many of those advances at the time).

FYI, I was raised in a devout Christian family, and I'm not disrespectful of Christians. However, I /do/ think its okay for an atheist to advocate their point of view.

 
13. Nov 2007, 02:00 CET | Link

The /principle/ behind the tenet is:

- /decouple/ components

 
13. Nov 2007, 02:01 CET | Link
the inclusion of "or life" in the last statement makes it sound as Just Another Tenet From Another Religion.

Well, this is actually a common rhetorical trick employed by the faithful in debates with the faithless. It usually goes like this:

But isn't atheism just another religion?

Certainly, atheism is a belief (more precisely, a /dis/-belief), but not all beliefs are religious beliefs, not evel all /strongly-held/ beliefs.

In particular, atheism is not an all-encompassing moral world view. Knowing that a person is an atheist tells you very little else about them.

Nevertheless, I don't mean to offend the faithful in this post. Certainly there are many deeply intellectually curious religious people.

 
13. Nov 2007, 04:36 CET | Link

Great post, too bad its somewhat unfair to the billions of believers in this planet. After all, one imagines somebody like Saint Augustine is more fair and open about discussions than your average internet geek talking about computer languages.

I believe you are making a case against fundamentalism in general (not just the religious).

Still, your point is very valid. And the tenet cited in your post is ridiculous.

 
13. Nov 2007, 08:54 CET | Link
After all, one imagines somebody like Saint Augustine is more fair and open about discussions than your average internet geek talking about computer languages.

LOL, great comment :-)

 
13. Nov 2007, 22:24 CET | Link
Worst of all, religions set up absurd laws that no adherant of the religion can possibly obey (do not covet thy neighbours wife

LOL, Gavin is there something you are trying to tell Mrs. King ;)

 
14. Nov 2007, 01:02 CET | Link
Javeed

Just a quick point that I didn't see anyone else make:

the orderProduct method that Xavier mentioned does indeed alter the state of the Order object but only indirectly. One can say that the state of the object is truly only exposed to the orderProduct method (which is part of the object itself) and that the orderProduct method exposes functionality and not state.

 
14. Nov 2007, 01:37 CET | Link

Javeed, surely my original quote that methods ... export .. state is just another way of saying /exactly/ what you just said. Stop playing word games.

 
15. Nov 2007, 03:01 CET | Link
Marcio

Maybe getAddress() is a little rude and gives the impression that it has rights over Order state. Maybe we should change it to pleaseTellMeYourAddress(). ;)

 
15. Nov 2007, 18:27 CET | Link
Andrew McVeigh | andrew.mcveigh(AT)gmail.com

Disclaimer: I've been an OO convert for a while.

I think the fundamental tenet you cited is really a simplification of the notion of modeling some aspect of the world via software. (A tenet is often a facade for simplifying a more complex set of rules. The key is knowing when to break the tenet). OO came from a simulationist perspective. And for all its faults this way of classifying the world does work well in most situations. I mean, you have to allocate logic and responsibilities somewhere, right?

Consider a simple example of responsibility allocation in the real world. I'm on a translatlantic flight and the captain flies the plan, but also wears a watch so he knows the time. He uses this time to sequence his activities without me telling him -- it's his job to fly the plane. Someone can ask him to fly the plane to Houston, without giving him precise instructions and he doesn't have to send all the plane instrumentation data back to somewhere else -- it's contained. However, if I ask him, he'll tell me the time (exposing internal state). It's a judement as to how much information is passed and at what level. But fundamentally, an object has responsibilities that it must carry out and it should have access to appropriate data.

So, to me the objective behind your OO tenet is to allocate behaviour appropriately over a simulated model of a particular situation. Clearly you get information leakage, sometimes it is desirable. For instance, I ring up the bank and ask for my statement entries -- this is a direct channel. The judegment is knowing what to expose.

And the objective behind the objective I've just cited is to minimize the effect of change when evolving a system. This insulation to change is something that is exhibited in the real world. We can't change our physical abstraction just because we have some extra data or some extra logic. We may however, reassign responsibilities and pass new data between entities.

Of course, rules are made to be broken. For instance, Hibernate is designed to provide an ORM layer and access to your data. As a consequence in that situation, it's perfectly ok to expose the data -- that's the domain.

Cheers, Andrew

 
28. Nov 2007, 02:32 CET | Link

Nice post. I would say simplicity is the only tenet I obey when programming is concerned.

Post Comment