Blog from March, 2013

There are many articles out there dealing with the accessor and mutator methods (getters and setters). They came together with the Object-Oriented principles. Information hiding says that the internal state of an object must be hidden from the outer world. That is, the fields it uses shouldn't be available. Yet, sometimes we have to query the state of the object, and even may want to change that state. Directly accessing the field representing the state is considered to be a bad practice (the field shouldn't be available), therefore a method must be provided to retrieve the value of the field. This method is the accessor method (the getter). Similarly, a method might be provided to change the value of the corresponding field. This method is the mutator method (the setter). Usually, the signature of these methods follow the <Type> get<FieldName>() and void set<FieldName>(<Type> newValue) notation. So we are safe, we strictly follow the OO principles, right?

Wrong!

We just mimic the OO theory. Consider the following code snipplet.

Direct access vs accessor/mutator access
class MyClass1 {
    public int counter;
    private int otherCounter;
    public int getOtherCounter() { return otherCounter; }
    public void setOtherCounter(int value) { otherCounter = value; }
}

class UserClass {
    public void userMethod(MyClass1 obj) {
		int val = obj.counter;
		obj.counter = 2 * val;

		int otherVal = obj.getOtherCounter();
		obj.setOtherCounter(2 * otherVal);
    }
}

What's the real difference between directly accessing the "counter" field, and using accessor/mutator methods for the otherCounter? Not much, isn't it? The only advantage is that by using the methods, the implementor is free to change the type of the variable later (e.g. to long). The methods will work none the less (yes, I know that you are smart enough to spot that converting the long otherCounter to int might lead to information loss and application misbehavior. You're right, so we might change the original contract and throw a UnsupportedOperationException - which is a RuntimeException, therefore the exception environment rule is not enforced, even the extended signature remains the same. Well, almost, but that's another story, so just let it go this time).

Comment: If you know what I mean under the term "contract", you're safe to skip this paragraph.
The term "contract" in this context means the specification given together with the class. That is, it describes all the details what this class is for, how it behaves, what kind of operations/services it provides, and so on. That's what one sees in the API docs, which is used by those who are going to utilize my class. Once it is published, care must be taken to preserve the backward compatibility, which allows the already existing users to upgrade to the newest release whenever they find it appropriate. In the OO world, it is allowed to do any changes in the internals of an object, as long as the contract is kept.

So using the getters/setters this way is rather the profanation of the OO principles than following them. After all, is it indeed an information to be exposed to the public that my class uses a counter? Unlikely. In most of the cases, definitely not. Then in some other cases it is. So how could one decide whether a field should be exposed to public this way or not? The answer lies in the OO design. The real question to ask is, whether my field represents a business entity, or it is just a technical aid. In the former case, it is okay if we provide accessor and mutator method for that field, and in the later case, we should avoid that (well, never say never, so there might be cases when it has its own merit; see more about it later). Consider the next code snipplet:

Access business info, not implementation-specific one
class Person {
	private String familyName;
	private String middleName;
	private String givenName;

	public String getName() { return givenName + " " + middleName + " " + familyName; }
	public String setName(String name) {
		String[] parts = name.split("\\s+");
		givenName = parts[0];
		if (parts.length == 3) {
			middleName = parts[1];
			familyName = parts[2];
		} else if (parts.length == 2) {
			middleName = "";
			familyName = parts[1];
		} else {
			// do whatever
		}
	}

I know - the implementation of setName should be smarter than just that. But first, it is clearer this way, and second, many programmers addressing only the US market might live with that easily. After all, we, poor Eastern-European programmers, had to live with the ASCII character coding for long, and we were stranded with our funny accented letters (and don't even mention our Asian friends, who came off even more badly for long). So just let it this way, and concentrate on the real issue instead.

In this code above, we provide access to the "name" as a business conception. No access to the "family name", "middle name", and "given name" - those are the implementation-specific parts of the conception. Suppose we have to sell the code to Indonesia, where there's a tribe in that every person has only one unique name. Suppose we have to sell the code to Philippines, where people may have four or even more official name tags. Suppose we want our application to run in Spanish or Portuguese environment, where some noble persons may have names like "Antonio Coimbra de La Coronilla y Azevedo". Our application should be reviewed fully, finding all the occurrences were we use the fact that the name consists of two or three parts. But if we use the approach above, the rest of the application knows nothing about the internal structure of the "name" business entity, so we might make the necessary changes in this "Person" class, without having to rewrite half of the application. Conclusion is simple, due to the fact that the class provides accessor and mutator methods to access and mutate business entities, and that it is definitely legal for the rest of the application to know about this business entity, therefore the usage of the accessor/mutator method is well put. Were we providing access to implementation-dependent terms (how we represent the "name" business entity internally) by such methods, we definitely would do harm.

Conclusion 1: Accessor and mutator methods should allow access to business entities, not to their implementation-dependent representation.

I might word it this way too. Using the accessor and mutator methods must be a design decision, and not a mere question of convenience.

So far so good, half of the story is perhaps told. Now we know when to use these methods. The next part of the story is about the how. How do we use them properly.

Suppose you go to your well deserved holiday, and you give the key of your house to your brother, and ask him to keep an eye on it. When you return, he is waiting for you on the airport, and gives you back your key. It's harmless, you don't see a scratch on it. Yet, you'll ask him immediately whether everything is fine at home or not. The state of the key says nothing about the house of that key it is. Now suppose we have a data model, which uses a List internally to store the data, and generates events whenever new items are added to that List, or items are removed from it.

Data Model
class DataModel {
	private List<MyDataItem> _data = new LinkedList<MyDataItem>();

	protected void fireEvent(final DataModelChangeEvent event) {
		// notifies the registered event listeners about the change - code omitted for better visibility.
	}

	public void addItem(final MyDataItem newItem) {
		_data.add(newItem);
		fireEvent(new DataModelChangeEvent(this, ITEM_ADDED, newItem));
	}

	public void removeItem(final MyDataItem itemToRemove) {
		_data.remove(itemToRemove);
		fireEvent(new DataModelChangeEvent(this, ITEM_REMOVED, itemToRemove));
	}

	public List<MyDataItem> getData() {
		return _data;
	}
	public void setData(final List<MyDataItem> list) {
		_data = list;
		fireEvent(new DataModelChangeEvent(this, MODEL_CHANGED, null));
	}
}

I'm sure now you have the point, but just allow me to emphasize it. The key is the reference returned by the getData method, and the house is the content of the list. In the model, whenever an item is added or removed, the notification is sent automatically. Then, for whatever reason (e.g. due to a misinterpreted performance enhancement), the List is exposed to the public. Yeah, the _data will refer to the very same List instance, regardless what happens in the code that calls the getData() method. But the content of the list is not safe any more. Whoever grabs a reference to the list (that's what the getData method provides), may make changes by adding or removing elements - and the model won't know anything about it. That's, ladies and gentlemen, is one of the best ways of inducing hardly discoverable, randomly occurring bugs into our application. In this particular case, the solution is simple - use the Collections class to create an immutable version of our list and provide that reference to the public. Alternatively, and if we have to allow the external code to change the content of the list, then instead of giving the reference, implement the Iterable interface, and return with a local implementation of the Iterator, which sends the proper notifications. But all these are possible only because we're talking about a collection. But the problem is more general than that - if part of the state of the object is another object (and a reference to that other object is held), then we shouldn't allow access to that other object, unless it is immutable. And how to do it in general? Sorry, no general solution exists. It's our responsibility to keep this rule.

The mutator method is also unsafe, although at first one might think it isn't. But what if the caller keeps that reference that he has passed through, and makes changes in the list in a later time? Similar problem, and the solution is also easy - instead of storing the reference, create a new List containing the very same items.

Conclusion 2: Whenever the accessor returns with objects, or the setter receives one, do not allow the direct usage of that reference, unless the referred object is immutable.

Finally, since it is very rare that universally acceptable truth would exist, therefore it is worth to note that there are cases when both of the two rules above should be broken. One such case is the data object, traveling between the client and the server (or vice versa). There, it is not just well but even wished that the object be serialized upon sending, and deserialized upon receiving. There are general frameworks that use getters and setters during the serialization and deserialization. In this case it is allowed to "expose" implementation details - after all, we're not dealing with business processes right now, we have to take care of mere technical problems, namely transferring data from one computer (e.g. the server) to another (e.g. the client). So it's actually not breaking of any of the rules above. However, in these cases, extra care should be taken to avoid the misuse of these getters and setters - they are only for sending and receiving information, and not for any other purposes.

A good developer suceeds even if his business domain knowledge is rather poor. However, as soon as he is going to be really useful engine, he might want to suggest solutions, then it is worth to learn all of the itsy-bitsy details of the domain, and he doesn’t consider any small information chip to be „unnecessary”. The next fable was written with having this thought in mind.

Once upon a time, there was a lead software architect. This said architect picked up the phone one day.

’Abraham Smith.’

’Hi Abe, it’s Zach. I am going to send you a doc. We must make a decision this week whether we’re going to apply for this job or not. It worth a few billions of dollars, and it fits well for us.’

’But chief, you know that we have a delivery deadline on the next week, currently my hands are full with the code reviews, I have to evaluate the results of the integration tests too, and what’s even more, I have to create the design plans for the next phase.’

’This later is not urgent, I’ll give your people some documentation tasks, they are always late with that anyhow. But the decision is very urgent, so please just put aside everything and read the docs. I want to know whether we’re able to do that or not, and give me a rough estimation too. I’ve checked it briefly, and by my opinion the specs are very detailed, and just in case, there’s a phone number to call if you have further questions. They promised that the phone will be answered around the clock.’

’Okay boss, as you wish, I’ll do that.’

’Great, then I send it immediately’.

Click.

’We never had to decide with similar urgency’ thought Abe. ’Anyhow, the assignment is just an assignment, whatever it might be, and setting up the priorities is the job of the management. Damn it though.’ he added, because his design plans for the next phase were half ready in his head, and those will be well forgotten, and will have to restart the whole stuff.

’Let’s see, mission statement, vision, why the hell this sonofabitch sends those goddam docs, oh, all right, here’s the requirement specification. So let’s just start.’

During the next many hours, Abraham worked hard at the specs. It was about a remote controlled vehicle, and since the company has just finished successfully a similar project, therefore it seemed to be a very achieveable task. There were a few tricky requirements – e.g. the navigation was ordered to be done by the analysis of the position of the Sun and the main starts instead of the accustomed GPS and compass.

’How stupid, and they’ll blame us if the sky is covered with clouds by night and the stars are all invisible, and the vehicle just stands there still and cannot go anywhere. Let’s just add a GPS module too, that’s just nothing for the hardware guys and then it'll be there as a reserve just in case of need for our program’ thought Abraham.

He went through the requirement specification thoroughly, paid extra attention to the nonfunctional requirements. He again has found some odd requirements, like extreme operational temperature ranges, very steep slopes to climb, but these – as they were mostly the problem of the hardware people – were mostly ignored by him. He has collected the necessary features, made estimations for each (partially based those estimations on the experience they’ve collected during the project of the just recently finished remote controlled combat vehicle they’ve just delivered to the Navy), then send back the summary to his boss.

’From our part, it is possible and takes these many hours, if the engineers will give us the hardware there won’t be any problem with our software.’ wrote he with pride.

One and a half year spent, the vehicle was delivered. One month later the first bug report arrived.

’The vehicle cannot fulfill the claim of responding with 1 second!’

Abraham saw his boss, whether it is possible to visit the customer or not, because they tested the vehicle on a very extreem way that the response times were closer to one millisecs that 1 hundredth of second. The boss gave a phone call, then pushed the receiver to Abraham.

’Hallo, I’m Abraham Smith the lead architect of your remote controlled vehicle. We’ve just received your bug report, and I would like to field check the vehicle because we never ever experienced such a delay.’

’I’m afraid it’s impossible, it’s on the Moon right now!’ was the answer.

’But... Well... and from where do you remotely operate it’ asked Abraham.

’How you mean from where, from the mission control room of the Kennedy Space Center of course, where else?’

’Oh, I understood. Thanks for the info then, we’ll try to find a different way then’ said Abraham, and disconnected the phone. He was very angry, but he knew that it leads nowhere to howl with the customer, not without asking the boss first.

’The distance of the Moon is well over 200 thousand miles, the light cannot even reach it within a second, jest to even return!’ bellowed. ’Why these damned sonofabitch bastards wrote that they want to remote control the vehicle on the Moon from the Earth?’

’But it was written, it was clearly stated both in the mission statement and the vision!’ said Zach.

’Shit, I never read them...’ stammered Abraham. ’I had not much time, and I thought there won’t be any useful info in them, those are written for managers.’

’Well, then I recommend to show up with a solution very quickly, otherwise we’ll have to pay a lot of penalty, which bankrupts us immediately’ answered Zach icily. ’Now begone and give me a plan by tomorrow’ added he.

Abraham gave it a lot of thoughts, consulted with the team, and find a solution. They’ll add a very detailed map about the Moon into to the remote client, and will extend it with a predict module, which will try to find out how will the vehicle react on the Moon to the just sent command. This predicted answer will be provided before the real answer would have been returned. The module will have some self-adjusting and self-learning capabilities too, so as the time advances, the predictions become more and more correct. The user will never spot it, he’ll just wonder how it’s possible to break the rules of physics.

He even became a bit more joyful, because it was expected to be an interesting development.

’We’ll need a few weeks, but the team will deliver’ he thought.

They indeed delivered. The NASA has checked it, and remain silent.

Meanwhile, the vehicle on the Moon crashed with an unknown object, which didn’t appear on the map. That was an alien spaceship. The vehicle sent the report back, and even mentioned that other small objects, capable of moving on their own, were departed from the unknown object, and approached. The self-learning program did not predict these events, so the built in filter just throw it away. No video cam was built in the vehicle, so noone in the control room was aware of the encounter, therefore it gave no suggestions how to react. So the vehicle – which has its own decision maker module – just by-passed the alien spaceship, and left the aliens high and dry. That alien civilization consisted of highly empathic beings, and among them the indifference was a deadly insult, and even worse, a kind of extreemly distasteful disease. Therefore they’ve notified their fleet which passed nearby, and after a few month the Earth was sterilized.

The NASA, which was going to trick Zach’s company to claim back some penalty by providing important information only on very unusual ways, and Abraham, who was going to save some time and therefore didn’t read three paragraphs, never knew that ultimately, they were the main cause of the final and total destruction of the human race.

And they laid stone dead happily ever after.