Fog Creek Software
Discussion Board




Anyone else aghast getters/Setters discussion?

Not the discussion on this board, the one at:

http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox-p3.html?lastpage=1#talkback

I'm just amazed at the negative responses, and the level of hostility.  I read Holub's article, and it seemed to me to be plain, vanilla, common sense about how OO programming is done.  Objects 101 stuff.

My take on getters/setters is pretty simple, and every good, experienced developer I know is on the same page.  Not because we're all geniuses or anything, just because this is where you tend to end up after a decade of OO programming (that is, making horrible mistakes for years and having to live with the results).  So:

Although not an "evil" in and of themselves, most of the time, getters/setters reflect a bad design.  Not *all* the time, of course, but usually, yeah, if you see getters and setters, it's because the OO stuff isn't right.  At least in C++ (can't speak to Java, or Python, or whatever).

And can someone enlighten me as to why Holub seems to attract such angry responses?  I've only read one of his books, which I thought was pretty good, and read one or two of his Java articles, but that's about it.  Is he abrasive in his postings, or something?  Just curious.  I mean, I never saw anyone get so *personally* worked up about Richter, Meyers, etc.  Maybe it's just one guy with a grudge?

I know this is last week's news, but it's been a long week, and I'm just getting to it...

Grumpy Old-Timer
Monday, September 15, 2003

Please explain how a getters and setters are inherient to bad design.  I'm interested.

christopher baus
Monday, September 15, 2003

I just love the OO world as I am new to it. I wonder why I feel that at any time the OO police will jump into my cube and start reviewing my code. Seems like very few people are good at OO design, but everybody sure does have opinions on the subject.

<my opinion>
In general the article seems reasonable, but I don't think I am savvy enough with OO to not use getters and setters more than 1% of the time.
</my opinion>

m
Monday, September 15, 2003

Who wants to feel stupid or inadequate? I agree with Holub's general point. But in real life, business goals and marketing are extremely close behind the SW developer, nipping at his heels.  So the negative reaction to his article is understandable. Why wants to hear that they've been doing it wrong for years, especially if they already knew it on some level already?

What I'm saying is that an absence of getter/setter methods in an object design probably reflects a genuinely profound depth of insight into a problem domain that many commercial companies will simply not tolerate in their schedules.

It simply takes *time* and *focus* to think through a design so thoroughly that every such implementation detail can be masked by a pure object interface.

PS: anyone catch the post by "Allen Holub" in the forum and the proposed Holub class objects that do everything? :-)

Bored Bystander
Monday, September 15, 2003

Today authors may need to talk about unusual to immideately take attention the readers. Most of great OO techiques and patterns are known and posted and new important ideas appear rarely. Personally I dislike Mr. Holub's articles because of multi-page explanation of basic things and sometimes tons of code, which I don't have time to read. :-)

Evgeny Gesin /Javadesk/
Monday, September 15, 2003

Well, getters/setters are pretty common, so when someone says that they're the result of poor design most people take it as a slam on their design skills. This leads to Mr. Holub not being liked.

To be honest, I think that there's a little to much 'I'm the only one who designs correctly' attitude in his books and articles. But I enjoyed his older writings. However now that he's a Java guy I don't really read him anymore.

Clutch Cargo
Monday, September 15, 2003

Bored - Yeah, I caught that - the funny part was that no one caught on it was a joke.  Or is that sad?  I can never remember...

But I disagree with you, theoretically.  I don't think it *has* to take any more time to do it "right" (for lack of a better word), does it?  Or does it?  I mean, you don't have to know all the interfaces up front, just code it the "right" way as it comes up.  So, when you find yourself about to write a setter or getter, stop a "invert" your thinking to do it the OO way.  What is your experience - is that just wishful thinking on my part?

I said "theoretically" because I've never successfully done it *completely* the "right" way on a really large project.  But (hopefully) I'm about to.

Grumpy Old-Timer
Monday, September 15, 2003

At one shop where I worked, we had a weekly night at the bar. It wasn't mandatory, but on that night there would be guys there, drinking beer and talking about code.

Taking an hour or two to relax over a couple of beers and think about your code is a good idea. I don't come up with my best ideas while I'm sitting at the terminal. It's invariably while I'm relaxed, lying awake in bed, drinking a beer, or contemplating a good meal that I just finished that I really get a handle on how to represent my data and my interactions.

My wine cellar is responsible for more good ideas than my screen ever was.

Clay Dowling
Monday, September 15, 2003

My biggest problem with Holub is that he most often presents his ideas as "the one true way."  A guy of his caliber and experience should know better.  A good understanding of the problem you are trying to solve needs to be your guide on a lot of these design issues, much more so than pronouncements from people illustrated by toy programs.

I prefer an approach like the GoF use for patterns.  Give a solution and illustrate the benefits and liabilities the solution implies.  This makes for much more effective selection of tactics.

To the point, I agree that a lot of time programmers are structuring their work like something you'd write in Pascal or C - they put a bunch of classes together to represent their data, and another group together that represent their algorithms.  This approach invariably leads to an overabundance of getters and setters, tight coupling, and other bad things. 

There are other situations, though where you need get/set behavior.  Blindly following the dictum to never use a get/set will just make the code overly complex.

My own personal opinion on things is that I don't even like the notion of a getter/setter.  Why should you be able to arbitrarily distinguish which values an object is storing and which are computed?  I prefer the more general notion that Bertrand Meyer uses based on commands and queries.

Finally, I wish Holub had centered his thesis on using primitive values versus using objects.  I think a great deal more learning might have come from that discussion rather than the tedious content of his current work.

anon
Monday, September 15, 2003

I don't agree with the getter/setters are evil thing.

Holub claims that 99% of getters/setters could be eliminated from my code by a "good designer". How does he know that? By that logic we just need 2 good designers in a room and they can iteratively eliminate almost all getters/setters in my code. No way.

Overuse of getters/setters may be bad, but there are plenty of valid uses for them. I think Holub is being either naive or inflammatory.

I was annoyed after reading that article. It felt like Holub was attacking use of getters/setters. That was fine, but  I don't see anything new or useful in that article to help me eliminate my getters/setters. The whole thing reminds me of some high-level "architect" that drops by to do design reviews without doing any real work.

NathanJ
Monday, September 15, 2003

Guess what? Getters/setters ARE OO design. They allow you to change underlying implementation details without having to change the public interface.

I read that article. He's, well, not very well informed.

Brad Wilson (dotnetguy.techieswithcats.com)
Monday, September 15, 2003

anon, you said something about getters/setters allowing you to distinguish between values that are stored and those that are computed.  Maybe you were thinking of setters in this context, but getters are the opposite.  Their whole existance is based on the idea of masking whether the value is stored in a variable or computed.  Otherwise there is no real benefit to using one rather than a public member variable.

Mike McNertney
Monday, September 15, 2003

Hi Mike,

Sorry I wasn't clear in what I was trying to say.  I was thinking perhaps that Mr. Holub was talking about getters and setters in a restricted sense - providing direct access to instance storage only.  Whether that is accurate or not was by no means clear to me from the article, though.  I wasn't sure if he was also using these terms in a more general sense to drive computations.

Hmmmm.... I think this explanation is even more unclear than my original comment.  Best I can do at the moment, though....

anon
Monday, September 15, 2003

Grumpy:

>> I don't think it *has* to take any more time to do it "right" (for lack of a better word), does it?  Or does it?  I mean, you don't have to know all the interfaces up front, just code it the "right" way as it comes up.

No, it doesn't necessarily have to take longer. But I just meant that figuring out the "right" interface that eliminates the need for getters/setters generally takes the most time, at least in my experience, because the "best" interface may not occur to the developer for awhile.

My own experience has been that my first class design try is often a throwaway and the second is the keeper. I often don't see the deficiencies in my first design until I actually try to use it within a larger design or in an application, at which time I readily see that the interface doesn't "fit". That all takes time. Not a lot of time, but appreciably more time than hypothetically coding it the right way the first time.

Meanwhile, most developers have a manager breathing down their neck to see results, "now"... so out goes the object purity and in comes the compromises and the quick-but-incorrect implementations.  The developer may feel, intuit, or even know better, but what's more important, keeping your job or satisfying your SW engineer aesthetic?

Because of this, I think edicts like Holub's are a recipe for resentment. They come off like haughty pronouncements to "eat cake."

Bored Bystander
Tuesday, September 16, 2003

PS: my background is about 0 java and mostly C++ and Delphi. But the concept is the same no matter what the language.

Bored Bystander
Tuesday, September 16, 2003

I think Bored pretty much hit it on the nose.  "Good" design takes time, whereas you can do a serviceable job in a shorter amount of time with a mediocre design.

And, frankly, that may be the best solution to the problem, from a business standpoint.  I love clean, elegant designs, and gorgeous code, but I am beginning to realize that in real life it pretty much doesn't exist, and isn't that practical.

All those OO design authors are working in an ivory tower.  In real life you have to get things done with a team of people who are not all OO superstars, and you of course integrate "dirty" legacy code.

The problem is that you can spend all your time working on a nice OO design, while your co-workers can actually get things done, hacking it up.  The problem is that the time-savings with OO design only pay for themselves in the next project/next 5 years, and often don't have a lot of impact in the short term.  And of course anything that is not in the short term is invisible to most management.

And yes I think "good" design avoids getters and setters.  There is no question that if you ask any of the "authorities" on OO design, they will tell you that getters and setters are overused, and you should code at higher levels of abstraction that getting/setting individual variables.  But of course in real programs they all exist.  In a lot of my programs I do very naughty things like exposing pointers to buffers in the class interface... but hey it works, and it's an intermediate solution between the legacy code it was converted from and a nice OO design.

Andy
Tuesday, September 16, 2003

Maybe the intention of the article is to show that a design with getters and setters can be replaced by a design without them.

To me, that says very little about the quality of the design.

Portabella
Tuesday, September 16, 2003

What the article was lacking was a clear example of a design with getters and setters, and an improved design without them. Now it was just a rant.

Frederik Slijkerman
Tuesday, September 16, 2003

If you want to see some real outrage and hostility, you should read the article prior to the one linked above:

http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html?

amused spectator
Tuesday, September 16, 2003

I think Anon hit the nail on the head: think queries and commands, not getters and setters. 

There are two main kinds of objects one deals with in a program: problem-domain, and solution-domain.  Problem domain objects represent real-world things, solution-domain objects are part of your application itself or are needed for the problem-domain objects to do their work.

In the case of solution-domain components, the vast majority of "setting" takes place when you create the component.  Also, solution-domain components tend to either hang around for a long time with the same settings, or are cheap to throw away and recreate with another set of settings.  This means that more often you want to configure them via a constructor, or some application-provided configuration mechanism.  However, like J2EE Session Beans, you don't really want these components to be stateful, so there's never anything really to *set*, you really only want to *configure* them.  Instead, they have command or query functionality, and take parameters to do something.

For problem-domain components, it's often the case that holding data is a big part of their responsibility.  However, this doesn't mean that you want to write client code that gets or sets attributes!  Instead, problem-domain components could have methods like "update yourself from a UI form," or "render yourself to a UI form", or "perform this action".  (Compare with the Naked Objects approach.) 

In practice, rather than actually putting code in each object to render itself or load itself, etc., you could e.g. convert to/from a hash table.  Then you write *one* getter, and *one* setter for the whole thing.  Or better yet, use reflection to do it automatically via field metadata.

Also, even problem-domain objects should have behaviors that focus on what the real-world object does (or what we'd like a "magical" version of that real-world object to do).  But, even if its whole job is just to hold data, you can still use approaches that cut out the whole getter/setter picture altogether.

Anyway, this is why I'd agree with somebody who said that proper design moves away from getters and setters.  Not because they're "evil" or because "you shouldn't use them", but because if you're really doing OO design, you would rarely *need* them for anything.

There's another design principle that also tends to lead you away from getters and setters: immutability.  Or to put it another way, "elimination of side-effects".  Any time you change an object's state, you create potential side-effects, making the program harder to reason about.  But that's a big subject, worthy of a thread all on its own.  :)

Phillip J. Eby
Tuesday, September 16, 2003

how do you do mvc without getters/setters?

i like i
Tuesday, September 16, 2003

Phillip, great explanation of the theory. I agree with everything you said and you put what I could not quite say myself into words. I think the main "problem" with getter/setters is that they are a fragmented set of operations that must be coordinated properly by a "client" application.  You pretty well summarized this notion.

And I recognized immediately where Holub was coming from. If the user of a class has to remember that properties blort, blip and bleep need to be assigned in some order or with some relationship to each other, then that is exposing some (not all) of the internal state of the object, which the class design itself should have abstracted out.

However, some object types naturally have a 'set of properties' interface: text for one (font size, font style, font family, etc etc.) How would one boil the "query interface"/"command" paradigm down for classes like this? At *some* level, some programmer has to assign a list of property values that are of fundamental data types.

Getters and setters are more useful than exposed member variables because at least the 'setting' parts can have attached code to keep the internal object state consistent.

After considering all this, I think that getters/setters are an intermediate stage of object orientation. They may be completely necessary at some times, and at other times they may be the best you can do if management hasn't given you sufficient time to refine your design.

Bored Bystander
Tuesday, September 16, 2003

--
In practice, rather than actually putting code in each object to render itself or load itself, etc., you could e.g. convert to/from a hash table.  Then you write *one* getter, and *one* setter for the whole thing.  Or better yet, use reflection to do it automatically via field metadata.
--

So now instead of a bunch of hard to maintain get/set code you have a giant hashtable containing all of the attribute data. If you want to change just one field (like the color of a widget) you'd need to populate a hashtable and send it in rather than just calling the method. How is that more maintainable?

Also, using a hashtable or a reflection mechanism takes a lot of control away from the object itself. How does an object veto a change or perform formatting of a datafield to multiple types (such as a thermometer with both getCelsius and getFarenheight temperatures, but stores internal values in Kelvin) ?

I know it's possible to avoid getters/setters, but I've rarely seen these avoidance techniques actually make the code cleaner.

NathanJ
Tuesday, September 16, 2003

"""how do you do mvc without getters/setters?"""

Eh?  What do getters and setters even have to do with MVC?


"""Getters and setters are more useful than exposed member variables because at least the 'setting' parts can have attached code to keep the internal object state consistent."""

Whaaaa?  I never said anything about exposed member variables.  That's even crazier than having getters and setters.  For the scenario you described, why wouldn't you use something like 'setProperty(property,value)'?


""""So now instead of a bunch of hard to maintain get/set code you have a giant hashtable containing all of the attribute data. If you want to change just one field (like the color of a widget) you'd need to populate a hashtable and send it in rather than just calling the method. How is that more maintainable? """

Who said you had to populate the whole hashtable?  That was just *one* idea of how to solve it.  Circumstances vary.  What's your use case?


"""Also, using a hashtable or a reflection mechanism takes a lot of control away from the object itself. """"

Huh?  The *object* is what should be using the hashtable or reflection mechanism.  And/or, the object provides metadata to control the reflective mechanism.  For example...  suppose you have a naming convention for member variables and for methods, similar to the JavaBean patterned names.  The reflective mechanism could choose to set the field or call a setter if one was present.  Then you wouldn't write setters for anything that didn't care one way or the other.

The annoying thing is that Java doesn't give you the ability to just say 'foo.bar' or 'foo.bar = something', and have it be determined by the object whether there's a getter or setter involved.  It's only the object that should know this!

In theory, this is so that Java can run quickly, by having bytecode access member variables directly.  However, everybody then turns around and writes getters and setters anyway, so you pay the method call overhead all the time anyway, and have to type the extra letters and parentheses in your source to make the call.  Feh.

It seems to me that the most practical approach might really be to just use a tool like AspectJ to advise member variable manipulation whenever you actually needed to trap updates, and just use public members instead of getter/setters.  At least, it'd be worthwhile if you were already compiling your code with AspectJ.

Phillip J. Eby
Tuesday, September 16, 2003

--
What do getters and setters even have to do with MVC?
--
When I think of MVC I always think of a data layer populating data beans with set methods and then the view widget components call some get methods on the data objects to find out what to display. So a key piece of building an MVC application is that you have a domain model that supports get/sets for communication between the layers. I may be wrong on this ... maybe there is a better way to do it.

--
Who said you had to populate the whole hashtable?  That was just *one* idea of how to solve it.  Circumstances vary.  What's your use case?
--

I guess I don't understand what you meant by hashtable.

As far as populating the whole hashtable that's not what I meant to say. It seems to me that you'd have to at least instantiate a hashtable and put your property into the hashtable and then call the setProperties() method on your object. So just to set one property you need to instantiate a hashtable and populate with the one value to change.

This is the way I've always seen the hashtable method used to populate fields.

--
"""Also, using a hashtable or a reflection mechanism takes a lot of control away from the object itself. """"

Huh?  The *object* is what should be using the hashtable or reflection mechanism.  And/or, the object provides metadata to control the reflective mechanism. 
--
I'm thinking of a simple set method that looks like this:

setHeartRate(int newRate) {
  assert(newRate > 0);
  rate = newRate;
}

It seems like checking that would be harder if you used this hashtable or reflection stuff. Your reflection solution sounds like it would avoid that, but it seems like its making the code more complicated instead of easier to maintain.

Anyway, this reflection/hashtable stuff still sounds like a "getter/setter" mechanism. I'm not sure what the advantages are other than reduced code size.

NathanJ
Tuesday, September 16, 2003

Regarding MVC: The "value object" pattern can be used in place of getters and setters.  For each simple value that's rendered by a view, you have a "value object" that holds the value, can be listened to, etc.  In Smalltalk, you can create a value object that encapsulates an object attribute, so that when the attribute is changed, the value object fires a changed event.

Unfortunately, Java doesn't have any way to do this without using an AOP tool.  However, it's quite straightforward to refactor generalized MVC into a domain-specific aspect; indeed some of AspectJ's tutorial examples touch on this.

Regarding hashtables, I do see your point.  I was forgetting that in Java it's several lines of code just to do the equivalent of this:

    foo.setStuff( {'bar':baz, 'spam':23} )

in Python.  Actually, in Python, you'd just do

    foo.setStuff(bar=baz, spam=23)

and 'setStuff' could either receive individual parameters, or a hashtable of the inputs if it wanted.

As for reflection being harder, it depends a lot on what you're doing.  If I'm implementing a large application, I'm probably going to want to use an MDA (model-driven architecture approach) in which much of the application is metadata driven.  That might mean either reflection or code generation.  See the book "The Pragmatic Programmer" for some very, well, pragmatic discussion on the use of such tools to create problem-domain frameworks.

But on your specific example...  what is 'setHeartRate()' for?  Does it set the goal heart rate of a treadmill?  The current measured heart rate?  Why am I *doing* this?  If the object is e.g., a heartrate monitor, why does it need a setter, since it presumably is taking input from an outside source?  If it's the user setting a goal heart rate on the treadmill, then this is a *command* anyway - presumably other things need to happen besides checking a value and setting a member variable!

Phillip J. Eby
Tuesday, September 16, 2003

Maybe a different tack will help explain my (and Holub's?) POV better...

OO design is breaking up responsibilities for things, assigning them to different objects (interfaces, really), and then hiding implementation details inside those objects.

Each interface should expose the bare minimum of methods or attributes required to accomplish the responsibility assigned.  The minimal interface is achieved when each exposed feature (method or attribute) is

1) highly-specific to the responsibility it fulfills, and

2) it provides behavioral value-add (i.e., it *does* something to fulfill the responsibility)

Getters and setters that do little more than validate the value and store it somewhere, rarely meet either of these characteristics.

Now...  not everybody *does* OO design.  Sometimes, even us pedants don't care if a particular design is OO.  That's cool.  But a proliferation of getters and setters is definitely a "smell" that suggests a non-OO design.  What your value judgment is from there, is up to you.

Personally, I look with disfavor upon a class or interface I've written when it has "too many" public attributes or JavaBean properties.  It smells like I'm 1) doing too much work, and 2) need to refactor the class to divide up its responsibilities a bit more.  If other code is actually using those attributes, it's also a sign that they're nosing into other objects' business.

Phillip J. Eby
Tuesday, September 16, 2003

I think a lot of the grumbling is centered on point #1 above:

"1) highly-specific to the responsibility it fulfills..."

Based on reading a lot of the responses it sounds to me like folks assume there are two approaches to things:

a.  Externalize a lot of marginal behavior (drawing, persisting, this, that, and the other) and equip classes with lots of getters and setters, or

b.  Internalize the behavior and dispense with the getters and setters.

So I think a lot of the folks decrying Holub's (admittedly unclear) advice favor approach "a" because it makes for smaller, cleaner classes.  In other words, they assume that without getters and setters, they are forced into position "b" making for larger, less cohesive class designs.

My own approach, and one that I think some of the others agree with is that there is a flawed assumption at work here.  Getting rid of getters and setters does not necessarily force you to internalize a lot of behavior.  You only have to internalize access to that behavior. 

Instead, you can leverage abstraction and polymorphism to help you out.  Phillip Eby gave a nice clear example of this in the earlier thread on this topic, and I'll (attempt to) add another one here.

If you have some business object you can probably list the businessy kinds of things you want to do with it as you normally do.  To this list you can add other operations describing how this object interacts with other objects out there.  For instance you can say we have to draw this object, print it, store it, combine it, and so on.  For each one of these operations, you can devise a suitable abstraction.  Behind this abstraction, you can hide variations on the common theme (storing to different places, printing to different devices, etc).

Obviously, this is not always the best or only approach to solving the problem.  It is, however, nice and clean, and it makes the extent of the object interfaces blessedly small, when it works.  It also gets the direction of dependency correct (see Robert Martin's book "Agile Software Development, Principles, Patterns, and Practices"* for a discussion about dependency in general and the so-called "dependency inversion principle" in particular). 

At the end of the day, though, I didn't pull any of what I just said out of Holub's article.  To my way of thinking the article was poorly written and unclear.

* http://www.amazon.com/exec/obidos/asin/0135974445

anon
Tuesday, September 16, 2003

Ok, thanks for the extra info.

I still disagree that getters/setters are bad design, but I'll agree that it is not a very OO technique.

I'm not sure the hashtable is more maintainable. Because in this example:
foo.setStuff( {'bar':baz, 'spam':23} )

what happens when you have a typo like this:
foo.setStuff( {'barr':baz, 'spam':23} )

I don't know python at all, but in Java that wouldn't cause any sort of compile error. Trying to call setBarr(baz) in Java would cause a compile error and let you know right away.

Anyway, I think this discussion is a little too complicated for a web forum. You could probably convince me further if I saw an application successfully doing this stuff.

NathanJ
Wednesday, September 17, 2003

*  Recent Topics

*  Fog Creek Home