The question is, what are we trying to achieve when we name an object? This may sound like an unlikely question as naming objects isn’t a rare occurrence; it’s something we do everyday. Bob Martin in his book Clean Code states that the name of an object should “reveal its intent”, which broadly means that it should tell us why it exists and what it does.
As an example, if you’re reading someone’s code and you come across a class named A, then like me, you’d be completely confused. What does class A do, why is it there? There’s no way you can work this out from its name; its intent is completely hidden. Now that’s an extreme example, but I’m sure you’ll agree that there are examples of class names which sound plausible, but aren’t all that clear. In my last blog I gave an example of a class named XMLDataProcessor and said that it was badly named. It fits the ISA noun rule in that you can say ‘a XMLDataProcessor’, but it doesn’t reveal its intent: which XML data? From what feed? And the word ‘processor’ tells us it’s doing something, but what? And anyway, isn’t ‘processor’ a weasel word?
In my last blog I hinted that various techniques for discovering objects had been documented over the years and that these include:
- Classical Classification
- CRC cards
- Informal English Descriptions
The idea that you can classify objects into sets or types is not new. It comes from the likes of Plato and Aristotle in the classification of plants and animals using a technique similar to Twenty Questions1 and has been used over the ages by many other philosophers. The idea of class classification is that you use related properties as the criteria for ‘sameness’ and that these properties do not have to be just measurable characteristics, but also include intangible properties such as observable behaviour. Shlaer and Mellor2 used these ideas to propose the idea that classes generally fall in to one of the following categories:
- Tangible Things
- Roles
- Events
- Interactions
...to which you can assign your system artifacts:
- Tangible Things - account, sales ledger, XML data
- Roles - customer, sales manager, employee
- Events - button pressed, XML message received
- Interactions - sale, meeting
In knowing what category an object belongs to, you can therefore figure out its intent (why it exists and what it does) and in knowing its intent you can come up with a really good name. For example: Account, Customer, SalesManager etc.
There several other systems of object classification available, but I’m not going to quote them here because, and this is the key question, who has ever done this? In all my career I’ve never seen anyone sitting down and classify their classes - ever. So, is object classification a load of intellectual nonsense? The answer is a resounding ‘NO’. If you look at one of the key tenants of good software design and current practice you’ll find the SOLID acronym, and literally in the center of SOLID you’ll find the Liskov Substitution Principle. To quote Wikipedia, this states that:
“If S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may be substituted for objects of type T) without altering any of the desirable properties of that program.”
A key programming concept that depends upon our underlying ability to discretely classify objects.
I think that the Liskov Substitution Principal can best be illustrated with an example, so I’m going to be totally corny and use the very simplistic example of a Dog extends Pet:
First I need to create a Pet class...
class Pet {
protected int somePetAmount = 2;
public Pet() {
System.out.println("Creating a Pet");
}
public void scratch() {
System.out.println("Pet is scratching");
}
public String getName() {
return "Unknown";
}
public void eat() {
System.out.println("Pet is eating " + somePetAmount);
}
}
...followed by a Dog...
public class Dog extends Pet {
public Dog() {
System.out.println("Creating a Dog");
somePetAmount = 10;
}
@Override
public void scratch() {
System.out.println("Dog is scratching");
}
@Override
public void eat() {
System.out.println("Dog is eating " + somePetAmount);
}
@Override
public String getName() {
return "Fido";
}
}
The crux of all this however, is in the code below where I can interchange Dog and Pet:
public void testLiskov() {
Pet myPet = new Dog();
System.out.println("My pet is called: " + myPet.getName());
myPet.scratch();
Dog myDog = (Dog) myPet; // cast required even though myPet ISA Dog
myPet = myDog;
myDog.eat();
myPet = new Pet();
System.out.println("My pet is called: " + myPet.getName());
myPet.scratch();
myDog.eat();
if (myPet instanceof Dog)
System.out.println("myPet is a Dog");
else
System.out.println("A Dog ISA Dog ISA Dog"); // This will print out
if (myPet instanceof Pet)
System.out.println("My Dog is a Pet"); // This will print out
else
System.out.println("A Dog ISA Dog ISA Dog");
}
...and the reason I can do this is all down to classification. To paraphrase Wikipedia:
“If Dog is a subtype of Pet, then objects of type Pet may be replaced with objects of type Dog (i.e., objects of type Dog may be substituted for objects of type Pet) without altering any of the desirable properties of that program.”
In summary, classifying objects is something we do everyday not just in our jobs, but also in our real lives too; it’s an involuntary reflex like breathing and is at the heart of good object design. But it only goes so far when deciding how to name objects and there are other techniques available, so in my next blog I’m going to take a look at CRC cards and consider if they’re all they’re cracked up to be.
1Wegner, P.1987. The Object Classification Paradigm in Research Directions in Object-Gilented Programming. MIT Press.
2Object-oriented Systems Analysis: Modeling the World in Data
No comments:
Post a comment