The discussion about properties had reached a fever pitch in the last weeks, and there is a great deal of dissent about the nature of properties. Are they meant for tools, are they the tool of the devil to seduce us away from the goodness of OO, or are they just an irrelevant preoccupation of programmers who have no tolerance for boilerplate? In this blog, I would like to argue that properties are legitimate design features, and that it is the job of a programming language to allow faithful mapping of design intent to code.
Chapter 3 in
Fowler's UML
Distilled discusses class diagrams. His first design
concept: properties. Fowler describes the role of properties in
OO design and how they are mapped to language features in Java and C#.
In Java, a public read-write property can be mapped to a getter and setter pair. The design concept
/** the name of this widget */ public property String name;
gets mapped into
/** Gets the name of this widget. @return the name of this widget */ public String getName() { return . . .; } /** Sets the name of this widget. @param name the new name of this widget */ public void setName(String name) { . . .; }
What's wrong with it?
Making the mapping from design to code clear and traceable should be the job of the programming language.
After all, why do we program in Java? You can implement classes in C—just use struct, write the virtual method tables with macros, and use some discipline.
Or, to use a more recent analogy, consider the enhanced for loop. Why do we prefer
for (String w : words)
to
for (int i = 0; i < words.size(); i++) { String w = words.get(i); . . . }
You could argue that the enhanced for loop is a deplorable sign of language bloat and that it is properly the job of the IDE to write the explicit loop.
Or you could argue—as the designers of this feature have—that the enhanced for loop reduces the cognitive load on the code reader because it is a more faithful translation of the programmer's intent, namely to loop through all elements.
I think the IDE argument is completely bogus. I don't care about the keystrokes. I know perfectly well how to get my IDE to type stuff. I care about reading the code later. When I read the explicit loop, I look at the indexes, the < sign, the ++. When they are all just so, I say to myself “aha—I rediscovered the intent; we really want to loop through all elements”.
As you can tell, I buy into the “intent” argument. Going back to properties, when I design a class, I think of properties, not getters and setters. I want that intent reflected in the code. I don't want to piece together a dozen lines of getter/setter code, checking that all the names and parameters are just so.
The most common argument that I hear against properties is “they are bad design—just like public fields”.
There is an essential difference. Once you expose a public field, you can never change the implementation. But with a property, you can start out with a trivial implementaton and refine it later, e.g. add error checking in the setter, or switch from field access to a computed result.
The usual trite example: Start with a trivial implementation.
/** the name of this widget */ public property String name; // compiler auto-generates trivial getter/setter
Later, refine it to
/** the name of this widget */ public property String name get { return fname + " " + lname; } set { String[] n = value.split(" "); fname = n[0]; lname = n[1]; }
(Yes, I know the setter needs better error checking. That will be the next refinement)
(Yes, I know that the number of keystrokes isn't all that different from using a regular old getter/setter. That's unimportant. What s significant is that the programmer intent is captured by grouping the implementation features together.)
Another
commonly voiced argument is: “You should not expose all internal
state through getters and setters”.
To which I say: “Amen”.
When designing a property, I ask myself whether this is indeed an intrinsic feature of the class that will always be there. Does it make sense to allow public read access? Public write access? The fewer properties, the better.
Some people argue that we shouldn't add property support to Java because clueless programmers would abuse it. But they already abuse it today, aided by the getter/setter auto-generation in the IDE. Is Eclipse a tool of the devil because it makes writing bad code so easy?
Design is hard. The class designer has the arduous task of producing a public interface that is rich enough to make the class usable and frugal enough to make it withstand change. I don't know how to simplify that task. All I ask for is that—once a capable design has been completed—the design intent is right there in the Java code, rather than making me recover it from a rubble of code.