Typical Programmer

A glittering performance of rare perception


Popular articles
All articles

About me
Hire me

Doing it wrong: getters and setters

14 Jun 2008

Every getter and setter in your code represents a failure to encapsulate and creates unnecessary coupling. A profusion of getters and setters (also referred to as accessors, accessor methods, and properties) is a sign of a poorly-designed set of classes.

A long time ago programmers discovered that reducing the scope (visibility) of data as much as possible led to more reliable and maintainable code. Before programming languages supported encapsulation or objects, programmers who cared to write better code followed best practices and idioms (what would be called patterns today) that encouraged limiting scope and data hiding. Back in the old days these ideas were discussed in terms of module strength and coupling. To learn the concepts without the distraction of OOP and “design patterns” terminology see Glenford Myers’ books Reliable Software Through Composite Design and Composite/Structured Design.

Today most of the popular programming languages support objects, limiting scope, modularity, passing by value, and sophisticated built-in types. There should be no reason to deliberately expose an object’s data to the rest of the code because the language can enforce encapsulation and data hiding. Correct object-oriented design requires an object to encapsulate and hide its data, and to expose methods that are verbs acting on the object (not on individual properties of the object). The large majority of accessors are nouns — nothing more than pointless proxies for direct access to the object’s private data.

Others have pointed this out — see Allen Holub’s article “Why getter and setter methods are evil” from JavaWorld, for example. But the articles questioning the use of accessors are outnumbered by articles explaining how to write them. As with so many programming topics there is more argument about the details than about the big picture. Java and C# developers have IDEs that generate getters and setters automatically, implying that accessors are a good idea. Instead I think the IDE should yellow-flag every public member variable and accessor — they are warnings of bad design.

This article was prompted by a discussion with some of my own colleagues about how to write accessors in ActionScript (Flex). Unfortunately by the time we had that discussion the code we are working on was already full of accessors and public variables; introducing a standard for writing accessors would do nothing to eliminate the coupling created by the leaky objects. It would, however, insure that the code looked the same no matter who wrote it, a greatly overrated goal in my opinion. I was too polite to criticize the code’s design, and too realistic to expect it would be rewritten because it fails to meet even minimal standards of modularity or data hiding. Although enough of us know good code when we see it, correct software design is a custom more honored in the breach than the observance.

Here’s an example of arguing about the wrong thing. In a popular blog posting “Python is not Java” Phillip J. Eby explains how to write accessors the Pythonic way:

Getters and setters are evil. Evil, evil, I say! Python objects are not Java beans. Do not write getters and setters. This is what the ‘property’ built-in is for. And do not take that to mean that you should write getters and setters, and then wrap them in ‘property’. That means that until you prove that you need anything more than a simple attribute access, don’t write getters and setters. They are a waste of CPU time, but more important, they are a waste of programmer time. Not just for the people writing the code and tests, but for the people who have to read and understand them as well.

In Java, you have to use getters and setters because using public fields gives you no opportunity to go back and change your mind later to using getters and setters. So in Java, you might as well get the chore out of the way up front. In Python, this is silly, because you can start with a normal attribute and change your mind at any time, without affecting any clients of the class. So, don’t write getters and setters.

At least Java has refactoring IDEs and compiler type enforcement that make changing the type or meaning of a public member variable easy to find and fix. In Python those kinds of changes would manifest themselves in a series of runtime errors. This kind of article explains why Java and C# programmers (wrongly) conclude that Python needs static typing and a refactoring IDE. The correct inference is that getters and setters should be avoided because they break the encapsulation OOP offers. Avoiding them for performance or refactoring reasons misses the point.

Frequently I find that accessors are one of the side-effects of over-application of object oriented programming, especially when coding proceeds without a clear OO design. If your language insists that you implement everything as an object you have to devise workarounds for situations that don’t fit the object/message (noun/verb) OOP paradigm. Pretty soon a folklore grows around how to “correctly” implement accessors, and programmers focus more on implementing accessors the right way when they should be trying to eliminate the need for them in the first place. You can see the same thing with other OOP workarounds — the lore surrounding singletons is an even richer mine of how to do the wrong thing the right way.

Programmers who learned how to write getters and setters — especially if their IDE wrote the code for them — transfer that baggage to new languages they learn. That’s why there is no shortage of articles debating how to write accessors in languages that shouldn’t need them, e.g. Python, JavaScript, Ruby.

I’ve written hundreds of thousands of lines of code in my career, much of it in object-oriented languages, and I have rarely needed to expose a member variable or write an accessor. When I have it’s been to fit in with a code base that is already full of exposed data and accessors; in code like that, correctly designed object-oriented code is a square peg because none of the other classes hide their data or act on other objects through messages.

Trying to stop the proliferation of accessors is futile, but you can stop using them yourself. In the same way that writers try to eliminate passive voice and weak verbs from their writing, programmers can try to avoid getters and setters as much as practical. And when you see code with rampant getters and setters or public member variables you can recognize it as the mess it probably is.

Comments

Keith Braithwaite, 14 June 2008 at 2:07 pm

What a coincidence. I’ve just been writing myself about the problems that come with the getter obsession, it’s relationship with some currently fashionable architectural choices, but best of all a technique that leads one away form it: TDD with Mock Objects.

The article is at http://peripateticaxiom.blogspot.com/2008/06/tdd-mocks-and-design.html

xyz, 14 June 2008 at 6:34 pm

As a student in CS, I would like to see a concrete example of this. Say you needed to populate a listbox with the names of you customers (Customer being the object with a member variable Name). How would you code this so that you don’t use a getter?

Tom Legrady, 14 June 2008 at 7:00 pm

If you have a have a bank account, you shouldn’t be arbitrarily setting the balance. I wish my bank would allow me to log on and set my balance to 50 million quad-google dollars, but they won’t. All I can do is deposit and withdraw. A bank account object should act the same way.

A listbox is never merely a listbox, other than in first year programming assignments… It is a set of … something. It may be a list of people whose phone numbers you know or a lineup of people waiting to be served. People whose phone number you know should probably be sorted; people in a queue should remain in arrival order. So rather than adding elements arbitrarily with a setter, you should use a method that implements a problem-domain activity: add_new_contact( person ) or enter_queue( person ).

Stephan Schmidt, 15 June 2008 at 9:03 am

“That means that until you prove that you need anything more than a simple attribute access, don’t write getters and setters.”

That’s funny. Because the evil in getters is not the code you need to write, but the concept. It breaks OO and encapsulation. Tell don’t ask. Someone who thinks he’s clever because he doesn’t use getters and uses direct attribute access didn’t understand the problem with getters.

Peace -stephan

Casper Bang, 15 June 2008 at 10:42 am

I’ve heard this one before, even from Gafter and Block when worried about mutability. But I also think it’s slightly on the puristic/idealistic side of things which is of course commendable when you are designing an API but not perfectly realistic. It neglects practical issues coming up when you do not hold a Master in CS or know the GoF material inside out, but have real software you need to get out the door to solve a business problem.

There are many examples of similar concerns, for all practical purposes, we ought to banish the “if” and “switch” statements since we should minimize branching and rely on polymorphism when we need it. The same is true about casts, we should rely on generics and covariance since it’s more type-safe. And really the list could go on, diving deeper and deeper into the whole anti-pattern vs. pattern vs. idiom debate.

So I think properties in a language is perfectly ok and avoiding it does not necessarily makes for better and simpler software. I do have an issue with getter/setter though, since it tends to blur the difference between a property accessor and a mutator (i.e. everything in Java is called getSomething even if it mutates the object or have other side effects).

Greg Jorgensen, 15 June 2008 at 11:08 am

I suggested avoiding accessors as much as is practical. You will run into cases where accessors are cleaner than any other solution — for example integrating with platform or third-party libraries, where you can’t change the class interfaces.

x, I am familiar with encapsulation and MVC, thanks. My example was intended to show that there are alternatives to accessors. Whether the alternatives are better than accessors or not depends on the situation.

Many so-called MVC frameworks and applications end up with lots of glue code in the controller, which is formally wrong but sometimes practically necessary. The view classes are supposed to get data to display from the model; the business objects in the model should not know about the view (UI). MVC seems to require the business objects (model) expose their internal data.

In general I opt for the more practical/less code solution over formal purity, but exposing so much internal data through accessors makes me worry about the broken encapsulation and the inevitable coupling. One way to confine the coupling is to wrap the model objects inside classes that can interact with the view, using composition or facades.

Referring to the simplistic example above, the addNameToList(listbox) method more naturally belongs to a DisplayableCustomer class that completely wraps Customer objects. The internal data of Customer objects would be visible to DisplayableCustomer but not to any other classes.

Daniel Michalikm 15 June 2008 at 11:32 am

@Mark, formatForPrint is often not trivial considering you must handle null atributes, insert commas etc.

Knowledge how to format address or patient name (including salutations,titles etc..) should be definitely coded in single place: either separate utility method/class or business/model class. In case formatting logic is outside business/model class you need access to attributes via getters.

I just suggest, that insted coupling business/model class to listbox there is better alternative just to compute String and let view layer to use it in any widget. This is also more clean from functional programming point of view: no side effects, threading issues – just determinstic idempotent computation.

anon, 15 June 2008 at 3:04 pm

How would you display your customer name in a UI widget like a TextField that is not collection oriented? Some method reachable from your Customer object has to output a String, right!? Whatever object that is disproves your point. And don’t try to pretend that toString() is somehow exempt because they failed to name it getString().

Khalil, 15 June 2008 at 3:52 pm

This is a beatten up topic for an alternative opinion you may find this entry by Cedric Beust interesting http://beust.com/weblog/archives/000022.html

x, 15 June 2008 at 6:31 pm

admin,

I apologize about the MVC jab, it was unwarranted. It’s pretty obvious you know about this stuff, I was just trying to express my puzzlement at your alternative solution just to prove the point that accessors are evil. Surely, you must have known that that solution was worse than the problem you were trying to solve in the first place.

Yes, accessors can be abused, like everything. If that was the point of your post, it’s a bit disappointing (as was Holub’s, back then). But used carefully, accessors are actually the best way to connect different parts of your code with the least coupling.

Greg Jorgensen, 15 June 2008 at 9:42 pm

There’s a pattern frequently found in comments to articles like this. The author writes “Avoid eating unwashed vegetables” and at least one person will comment, “What do you mean never eat vegetables? Are you nuts?”

The first sentence states my opinion pretty clearly: “Every getter and setter in your code represents a failure to encapsulate and creates unnecessary coupling.” I go on to advise avoiding accessors when possible and gently reminding my readers that objects are nouns and methods are verbs acting on the object; poking around the object’s internal data a big red flag that something might be wrong with the class design.

That is not the same thing as writing “Never use accessors.” Nor is linking to Allen Holub’s article as an example of another article on this subject the same as writing “Allen Holub is totally right and I agree with him 100%.”

If you think about your code and decide that accessors are the best way to go, great — no OOP police will knock your door down. On the other hand remember my article the next time you write or discover this kind of thing:

class Product
{
    private Number price;
    private Boolean taxable;
    ...

    Number function getPrice()
    {
        return this.price;
    }

    Boolean function getTaxable()
    {
        return this.taxable;
    }
    ...
}

// client code somewhere else...
if (aProduct.taxable)
    priceWithTax = aProduct.price * taxRate;
else
    priceWithTax = aProduct.price;
Your mileage may vary but I see that kind of thing all the time. What I am suggesting:

class Product
{
    private Number price;
    private Boolean taxable;
    ...

    Number applyTaxRate(Number taxrate)
    {
        if (this.taxable)
            return this.price * taxrate;
        else
            return this.price;
    }
}

Greg Jorgensen, 15 June 2008 at 9:48 pm

Khalil: Thanks for the link, good rebuttal of some of Holub’s points. I know this article is flogging a dead horse for some of us, but lots of programmers are still writing getters and setters that serve only to make private members public, because they are mindlessly following some half-understood rules that say “public members are bad” and assuming accessors are the answer because their IDE writes them automatically. So the message is not getting through.

It may be that bad programming is like bad driving — you can point it out and complain all you want but nothing much ever changes anyway.

bwtaylor, 15 June 2008 at 9:53 pm

Introducing a DisplayableFoo for every Foo in your object model violates the duplicate class hierarchy code smell. Why is this better than coupling to the fact that a customer name a string?

Unless you have an actual reason to think the customer name representation as a string may change, you are just over-engineering a solution to a problem you don’t know you actually have. YAGNI and “the simplest thing that works” counsel again this. If you know upfront you may need a different representation, or you discover this need later, then refactor customer.getName() to return a CustomerName object. This is not a “failure” of encapsulation – it’s deciding what is or isn’t part of the class contract and object model. Nor is it an “unnecessary” coupling. It is necessary to rely on the stable aspects of your code to avoid needless complexity.

BWT… the last time I checked “get” and “set” ARE verbs. Client code has no idea what the internals of getName or setName actually do, and the implementation details ARE hidden. The only thing that is special about get and set in java is that if you use them, have a no-arg constructor, and are serializable, you are a java bean and tooling can take advantage of your uniform interface to do more stuff for you, like a simple Introspection API, easier dependency injection, or expression language assistance to help with rendering views. You are going to have methods that do verbs to your nouns. It’s just a question of whether you want tooling to help with those verbs and whether you want to follow fairly standard conventions and use idioms that are well understood.

Greg Jorgensen, 15 June 2008 at 10:24 pm

bwtaylor: If I was actually writing the kind of toy application that’s been used to illustrate the comments I would completely agree with you. As soon as I offer a code sample to illustrate a point the arguments are about the example’s implementation rather than what it was attempting to illustrate.

There is more to coupling than types. You ask “Why is this better than coupling to the fact that a customer name a string?” If clients were only coupled to the Customer class by the name and type of Customer.Name there would be no reason to do anything more elaborate than make Customer.Name public. But take a more realistic example where there’s not just a simple String Name member variable for clients to know about.

A customer’s name might be two strings: first and last name (for sorting), maybe including a salutation and suffix. The customer name might be a company name and contact person for some customers, and an individual’s name for others. Customers that are corporations may have different formatting for their “name” for invoicing, email solicitations, direct mail, sales calls, etc. If you follow the getter/setter route and expose all of this information your Customer objects are leaking a lot of information, and client code has to know a lot more about customer names than just their implementation type.

Should programmers wait to address these issues until they actually arise? Of course — you aren’t gonna need it most of the time. But the kind of Customer object I just described is typical of what I would know I had to deal with before writing any code — I don’t have to wait until the Customer object needs more functionality, because it will be specified at least that complicated from the beginning.

With a more realistic Customer class proliferating accessors does exactly what I am warning against: the internals of Customer objects are exposed and client code has to know how to access and manipulate customer data.

The kinds of accessors I cautioned against are the proxy methods that do nothing more than expose otherwise private member variables. Yes, get and set are verbs but even if they were named read and write they would still be nothing more than proxies that serve no real purpose. Just naming a function with a verb does not mean it conforms to the spirit of OO design.

It’s the habit of automatically writing accessors instead of thinking about actions on objects that I am going on about, not whether accessors should ever be used or not.

Wouter Lievens, 16 June 2008 at 12:47 am

Exposing a Getter is only a problem when the getter itself isn’t part of your domain protocol. A Customer has a Name, and it’s every user of the Customer’s right to query for that name, so a Customer.getName method has as much place in the domain model as the Customer class itself.

James, 16 June 2008 at 5:34 am

I largely agree but it depends a little on the kind of object. Objects that are just data holders (like DTO) perhaps accessors are okay, or even using public member variables to begin with, as they typically have no behavior.

getter eradicator: http://martinfowler.com/bliki/GetterEradicator.html

MoffDub, 16 June 2008 at 10:00 am

Quite the coincidence – I just wrote a post about this:

http://moffdub.wordpress.com/2008/06/16/the-getter-setter-debate/

I find the topic thoroughly confusing and surprising that some people are advocating fusing UI and domain layers together to avoid accessors, while on the other hand, mindless getter and setters are used everywhere, even when they have no behavior.

The only thing I have even come close to concluding on this topic is that maybe getters and setters are OK at layer boundaries. And then this raises the question: if you add getters, then they are available to all classes, even those within the same layer.

Then you start thinking of a parallel class hierarchy to deal with this, and you’re back to another code smell. It’s like lighting a match in a wet paper bag.

Greg Jorgensen, 16 June 2008 at 10:22 am

James and MoffDub: Thanks for the links — good articles.

There’s no single right thing to do in every case, so as usual you have to decide what’s best case-by-case. Sometimes accessors are the least-messy thing to do because the alternatives introduce worse problems.

I think Martin Fowler got to the heart of what I was trying to say in his article: “[I]t’s still common to see procedures that pull data out of an object to do something, when that behavior would better fit in the object itself – a violation of the pragmatic programmers principle of ‘Tell Don’t Ask’.”

Aaron, 16 June 2008 at 2:05 pm

I think it’s fair criticism when people see an extreme view and ask for an example and the given example isn’t particularly good.

As a beginner coder working for someone who obsesses over best practices, I’ve had a lot of discussions about this sort of thing, as well as about the PureMVC framework (which we’re using for a Flex project).

To use your customer example, I’d create a customer value object that has a getProperName method that assembles the name out of whatever is available (Mr or Mrs? Junior? Hyphens?) and returns a string. Perhaps that method would be static so that we could use it anywhere we had that sort of information and wanted to get back the properly assembled salutation.

So the final signature would look like: (and this is AS3 code, not Java) public static function getProperName(first:String, last:String, prefix:String = “”, suffix:String = “”, lastNameFirst:Boolean = false):String

To go back to your taxable price example, your method name is confusing! Perhaps this is a stupid question, but why not have a public method get totalPrice():int which has the tax rate logic?

Or perhaps you could even have a private getter that adds the tax rate to 1, call it get taxMultiplier or some such thing and ALWAYS multiply price by that to return total price – then there’s no if/then.

That’s probably just an exercise in taking different coding ideologies to extremes. I’m not sure.

Stacy, 16 June 2008 at 3:18 pm

The way I solve this problem is to create a dual class hierarchy, one for behaviourally rich objects and one for anemic objects (DTOs). I’ve just found that the needs of these are too dissimilar to warrant keeping them in a single object and the presence of accessors in my experience leads very swiftly to procedural code. I use DTOs in my I/O layers (to and from forms, databases, messaging) and I use Domain Objects otherwise, I like to keep the domain objects immutable where possible.

Another approach is to simply annotate the data you require for display and then implement something which uses reflection to find the annotated fields and copy the data into the UI, Hibernate takes a similar approach, unfortunately with this approach the fields cannot be immutable.

I don’t know of any solution which isn’t a trade-off of some kind, I choose to make the trade-off that I’ve found leads to more OO code.

I’ve found the number of people who make careful choices about breaching a good design are greatly outnumbered but others who’ll hack in anything that helps them with their current (self created) crisis and though I wish I didn’t have to I found a need to erect barriers to these people.

MoffDub, 16 June 2008 at 6:40 pm

Here is something interesting.

Eric Evans, of Domain-Driven Design fame, is a fan of the Intention-Revealing Interfaces that arise when you avoid getters as much as possible. He has an example called TimeAndMoney, which is supposed to demonstrate DDD.

If you go here: http://timeandmoney.domainlanguage.com/ and open the file Money.java, you’ll see this amongst a lot of intention-revealing methods:

/**
* How best to handle access to the internals? It is needed for
* database mapping, UI presentation, and perhaps a few other
* uses. Yet giving public access invites people to do the
* real work of the Money object elsewhere.
* Here is an experimental approach, giving access with a
* warning label of sorts. Let us know how you like it.
*/
public BigDecimal breachEncapsulationOfAmount() {
return amount;
}

public Currency breachEncapsulationOfCurrency() {
return currency;
}

Interestingly enough, the method names of these getters still are intention-revealing because they send the message to other developers to know what you’re doing when you use them.

Peter Lawrey, 17 June 2008 at 1:31 pm

I would say trivial getters and setters break both the You-Aint-Gonna-Need-It and Don’t-Repeat-Yourself principles.

“In Java, you have to use getters and setters because using public fields gives you no opportunity to go back and change your mind later to using getters and setters.”

I would claim this is a poor excuse for adding getters and setters. You have an opportunity to change them if all your references are within your control and 95%+ of the time they are. I would call this refactoring.

You will find getters and setters are mindlessly added to code when years later they are still there even when its apparent they were never needed.

Another way of looking it is; Don’t add what you don’t need because once added, no one will be bother removing it.

thinsoldier, 23 June 2008 at 8:31 pm

@admin & xyz

I think either way is the way to go depending on the situation.

$simplelist->add($customer->Name);

Just a simple list that accepts simple strings from any source and I can’t think of any reason to make the Name private.

Now, as is often the case with my stuff, I don’t have a customer “Name” in the database. I have a firstname, lastname, companyName, and preferredName.

So if I wan’t to add just a client’s “name” to a list of things I would need a method to combine the first & last name into a single string (“John Doe”)…that is unless the preferredName indicates that the record is to be referred to by its CompanyName even though there is a firstname/lastname value present (some contact person probably entered by mistake by the user(there is a separate module for managing contacts at client businesses)).

Anyway, the code for that would be something like:

$simplelist->add($customer->getFullName());

and that would probably be my only “getter” (is it really a “getter”? there’s no actual object property or table field named “FullName”. I guess I should add FullName as a class property with a comment indicating that it only exists in the class and gets its value defined by running getFullName….)

$customer->addNameToList($customerlist);

the customer and and list objects as admin described it seemed more dependant on each other.

“The listbox object passed in would need a method to add a single name, so Customer::addNameToList(listbox) would in turn call listbox.add(this.Name).”

But I can think of situations where I’d need a special extension of the simplelist designed to visually format standard customerlist objects. So it’s good too.

Like I said, depends on the situation.

(disclaimer: I never did CS so I might be completely wrong)

thinsoldier, 23 June 2008 at 8:36 pm

…But I can think of situations where I’d need a special extension of the simplelist designed to visually format standard customerlist objects. So it’s good too…..

foreach($arrayOfCustomers as $cust) {
$customerlistFormatter->add($cust) ;
}

// some time later in the visible output code
$html .= $customerlistFormatter->render();

Actually the customerlistFormatter should probably expect to be working with an array of customer objects. So just skip loop: $customerlistFormatter->add($arrayOfCustomers) ;

(disclaimer: I never did CS so I might be completely wrong)

thinsoldier, 23 June 2008 at 9:08 pm

“The kinds of accessors I cautioned against are the proxy methods that do nothing more than expose otherwise private member variables. Yes, get and set are verbs but even if they were named read and write they would still be nothing more than proxies that serve no real purpose. Just naming a function with a verb does not mean it conforms to the spirit of OO design.” -Greg

If all the getter does is:

function getPrice()
{
return this.price;
}

Wouldn’t it make sense to not actually write any getter code and just use __get();

function __get($wanted)
{
if($wanted == ‘something_That_Used_To_Be_OK_But_Is_Now_Very_Bad’){ throw something }

if($this->$wanted){return $this->$wanted;}

return false; // or throw something else
}

… or something like that?

MoffDub, 3 July 2008 at 7:16 pm

I have written a new post on my blog that discusses a pattern-based solution to this topic:

http://moffdub.wordpress.com/2008/07/01/method-regulator-pattern/

GregM, 14 August 2008 at 10:04 am

Aren’t we missing something here and getting too extreme? I have read all sorts of articles on the getter/setters are bad idea, and they all seem to be too extreme. As I see it, the main idea is to NOT use accessors to just replace public fields, as that is bad. Having a way to “get” something from an object may be quite a reasonable thing to do. The idea is that if I “get” something from an object, it should be in control of what I get, and most often will give me a read only copy. A good example is the customer name thing, where internally the name is stored in pieces, salutation, first name, last name, etc. I should not be able to just get or set these pieces without it being part of some domain operation, but I think it is perfectly OK to ask that object for the customer name, and have it build it according to some naming convention. To say that such a getter is bad is wrong in my book because it takes the “no getters” idea too far. Building some complicated mechanism to do the same thing simply does not make sense to me. I think the same case can be made for “setters’, but in this case one must be more careful to make sure that the setting action really is part of some domain process that the object implements, so that the setting of the field is really just a side effect of the object doing it’s business. Giving things to objects and asking objects for things is not bad or evil as I see it, so long as it is not breaking the encapsulation boundary. This is the main thing to remember.

Andy Raybo, 27 August 2008 at 7:09 pm

Greg,

Mindful of your admonition about unwashed vegetables, I will confine my responses to an unequivocal statement you made in that response, and which you characterize as being the core of your position: “Every getter and setter in your code represents a failure to encapsulate and creates unnecessary coupling.”

The problem with this reasoning is that data hiding is only half a principle. The more complete idea is that classes should have an interface that minimally expresses their intended semantics, and all else should be hidden. Note that whether the data exchanged in that interface are objects or primitive types, or whether they are also instance variables of the class, is immaterial. If an accessor makes sense in terms of the semantics of the object, then any coupling it creates is justified, even necessary (subject to appropriate use by the rest of the program, of course.)

I wrote, ‘in terms of the semantics of the object’, and I meant it. If they are introduced to satisfy the requirements imposed by an external design decision in some other object, rather than in terms of what the class itself represents, then it is a warning of sub-optimal design elsewhere. In practice, it is much more likely that instance-variable getters are appropriate than instance-variable setters (yet few languages recognize this asymmetry). Generally, as you say, a proliferation of accessors is a warning that something is amiss. As design is a compromise choice between many possible alternatives, however, no simple rule serves to decide whether any particular case is good or bad. I didn’t think moral philosophy had much in common with software design, but this is a case where intention matters!

As for everyone who thinks it’s OK to mix up business logic and UI code in a single class, may I never have to read your code! This is surely a case of opting for fire over the frying pan.