Thursday, September 28, 2006

Confession Time

"A wise man changes his mind, a fool never" - Spanish Proverb

Well, at least it makes me feel better right? Well, I have a confession to make. In the past, I have argued for the use of accessors on instance variables. I liked accessors because they looked the same in the code as a method call and the flexibility. But, several months ago, I tried writing code without accessors. I was shocked by what I found about myself. First, it was hard after programming with accessors for so long and it didn't feel natural. But, I got over that in the first month or so. Second, I noticed that I broke encapsulation of my objects less. In fact, if I felt the need to access an instance variable outside of my class, I questioned myself thoroughly and generally tried to find another way.

I thought I was writing good code, but I was making little sins that added up. Forcing myself to use accessors only when necessary caused my objects to be more self-contained. I started writing smaller objects. My code got way better. So good in fact, that I find myself on the other side of the accessors debate.

Yes, I now frown upon the use of accessors by default. It leads to data structures (not objects) and controllers (not objects). The funny thing is the road to breaking encapsulation is one paved with small sins along the way. Besides, with today's tools, it's easy to switch the accessors if needed.

Oh well, I had to get that off my chest.

5 comments:

Andres said...

Just wondering... why should a sender know the message being sent is an accessor? What difference does it make to the sender to know that?

And in fact, 99.999% of the time it should not make any difference whatsoever.

So how come senders care? Perhaps THAT is the issue.

IMHO, if the thing is designed improperly, it is going to stay that way with or without accessors, with or without Smalltalk.

Blaine said...

Yeah, well, DUH!

Seriously, a sender should never care. The point was not to expose the accessors unless you need to. Take a Money object for example. Do you really care how the amount is calculated? It could be an Integer based on cents or a BigDecimal. It doesn't matter. I have found that keeping your object's internal under tight control gives better designs. You start writing smaller objects.

I just believe that by not using accessors by default then I'm not polluting my object with needless noise. I'm also making a conscience decision when I do decide to expose an accessor. It makes me develop better. It's too easy sometimes to just call the accessor simply because it's there. I know you could think about calling it then, but sometimes in the heat of the moment, you forget it's an accessor.

Staying away from accessors by default gets us away from procedural code.

Andres said...

I think this illustrates the issue pretty well, but does not yet state it clearly.

The problem is that developers usually write code in the first person --- "I send the message". Usually this is because of fear --- "objects, do as I say and otherwise stay frozen". With or without accessors, that is a problem already.

In my experience, procedural code in environments like Smalltalk is a direct manifestation of fear, or at least an inability to let go of control.

I use accessors for every instance variable. But I also put most of them in categories such as "private - accessing", and respect that by having other objects not use them from the outside. Typically, that leads to objects understanding useful messages such as doWhatYouHaveToWith:, instead of this:

anObject instanceVariableA: such.
anObject instanceVariableB: such.
mov cx, word ptr [es:bx]
mov dx, word ptr [es:bx+2]
anObject run

But... hey, just my opinion :).

Tim said...

Blaine - I've been trying a similar experiment, the bit that kept slapping me in the face was how to initialize instance variables from my class constructor.

Having a private wide #initialize method was fine but its a nuisance typing it in (and maybe this is just a tool problem) vs. using the generate accessors option and then doing

^self new fistName: blah; lastName: blahblah; yourself.

So I've been using categories. Of course now I should really extend my Lint checker to find calls to private from outside the calling hierachy, or maybe I should just write the darn CreateInitialze tool.

Tim

Anonymous said...

So, is your point that accessors should be used in moderation or not at all? I think, by your reply to Andres, that you are saying in moderation. I agree, although at times, it just feels good to setup everything and not worry about it later.

If instead, you are saying just use the variable directly. Well... that just doesn't feel very good. Inside my object, I still use accessors quite frequently. The overhead is minimal and I find the solution more elegant and desirable.

I understand your point and it is a good approach to disciplined design. I just can't help myself :)

While variables provide an object with structure and substance, the dialogue breaths life into the system, making interactionsh with the object, not just possible, but beautiful and desired.

Amazon