Wednesday, March 31, 2010

10 Reasons Why Accessor Functions are Better than Global Variables

Novices often read that accessor functions, such as lineWidth() and setLineWidth(), are better than global variables, such as LINE_WIDTH. But they usually only see one or two reasons why, hardly enough to overcome the clear simplicity of using variables.

So let me try to put the nail in this particular coffin with 10 different reasons.

By global variables here, I include things like Lisp and C global variables, and things like public C++ data members and Java instance variables. By accessor functions, I mean things like Lisp and C functions, things like public C++ and Java getters and setters, and things like properties that some languages support that are "variable-like" in syntax but "function-like" in actual semantics.

1. Readability

To make it clear that some variable is global, most languages have some naming convention to make them stand out, e.g., asterisks as in *current-color* in Lisp, and upper-case as in MAX_DATA_LENGTH in C++ and Java. But such conventions clutter up code badly. [When an experienced Lisper sees code littered with starred variables, her first reaction is "Asterisks! The gall!".]

Accessor functions however are just regular functions and need no such special naming.

2. Read-only access

Often there is global information that the user should be able to access, but not change. By defining and making public only a reader function, you can prevent users from changing information that can not or should not be changed.

3. Write-only access

While less common, sometimes there is information that needs to be specified that should not be readable, by some users at least. changePassword(old, new) comes to mind, here.

4. Uniform access to variable-like data

There's more to a computer than CPU and memory. There are clocks, I/O ports, system host information, and so on. Accessors like currentTime() offer a uniform way to access such information, without worrying about whether such information is stored in a memory location or derived from some other source.

5. Scoped values

Consider output line width. When we set it to 50 characters, do we mean that to apply to all output, including output to files, or just to output to the screen or to some window on the screen? With accessors, it's easy to extend the API
to allow values to be scoped appropriately, e.g., setLineWidth(debugOut, 50), without creating a slew of specialized variables.

6. Safe assignment

Consider line width again. What happens if someone says (setq *line-width* nil) or setLineWidth(-10)? With variables, the chances are nothing happens until later when printing is attempted, at which point an error occurs. With an accessor function, bad values can be caught and prevented or replaced at assignment time.

7. Assignment with special values

Consider line width once more. With an accessor like set-line-width, we can extend the values it accepts to include things like named standardized values, such as (set-line-width :wide) or setLineWidth(WIDE), where "wide"
is not the actual value but a key to look up some standard default value.

8. Assignment by example

Consider date formats. There are many ways dates can be printed: full month names vs. abbreviated month names versus digital months, two-digit vs. four-digit years, month-day-year vs. day-month-year, hyphens vs slashes vs. spaces and commas, etc. A clever way of making this complex combination of choices simple to specify is to allow the user to given an example date, e.g.,
setDateFormat("2/31/95"). This isn't the actual value stored, but a
value that can be used to construct the actual format object.

9. Assignment by parts

Consider default pathnames, e.g., the default pathname for the compiled
binary form of a source code file, or an XSLT-transformed XML file.
Even though it makes sense to store this internally as one pathname, it makes more sense to allow the user to modify pieces of it without worrying about the other parts, e.g., (set-module-binary-pathname :directory "Lisp:").

10. Traceable access

Many development environments, especially for high-level languages, don't make it easy to trace when someone gets or sets the value of a global variable. This is no problem with accessor functions.

Wednesday, March 17, 2010

The Next Revolution in Software Development

Don't miss the boat!

Training seminars in preparation now for the next paradigm shift. More extreme than extreme programming!

I refer of course to the outsourcing of development to even lower life forms than programmers: Algae Software Development.

Alistair Cockburn says: "I am really a blue algae, not a blue-green algae."

Learn how to do rapid web application prototyping in the C Web Engine Emulation Development kit, or C Weed.

Learn what it means to be really off-shore.

Become a Certified Scum Master today!

Tuesday, March 2, 2010

Early Client Value is more than just something that works

I'm currently teaching agile development in two very different contexts. One is a course for mid-level managers, most with no software experience. I'm also coaching a team of computer science and business students, doing a project in a course on innovation and entrepreneurship. In both courses, I talk about the need to deliver early client value via slices (my shorthand image for minimal marketable release).

Or, as I usually put it: How soon will you be able to say "Even if they cancel us, we delivered value?"

I contrast developing slices with a "foundation up" approach that works on infrastructure first, rather than some end-to-end deliverable.

Both groups got the idea of getting something working that the client can use, but both made the same mistake in their release and iteration planning. Their first releases were systems that supported basic operations like adding, deleting and displaying items. For a hypothetical system to manage software purchases, users could add records of things purchased and query along various parameters. For a social network site project, users could upload pictures for sharing.

These are end-to-end, and they do make sure things are working, but they are not valuable. These things can be done with existing freely available tools. If the project died tomorrow, the client would not have anything they didn't have already. These are minimal releases, but they are not marketable releases.

Every system has a reason for being, a need that's currently not met. Early value means something that makes some visible progress towards meeting that need. The software purchasing system was originally envisioned as a way to reduce costs by seeing the best prices that divisions in a company had managed to get recently. Therefore, an initial release and early iterations should focus on displaying data, not entering it, and demonstrating possible savings. The social network site first release should show something about sharing pictures or other media not currently possible or easy in existing sites.

Note that in both cases, it may turn out that the original vision is infeasible or much harder than thought. Better to know that early. And, in the purchasing project, the initial release might not need to have any user interface for adding purchase records at all. A table from an existing purchasing database generated by a manual query may provide enough real historical data for the system to fulfill its original mission well enough for a marketable release.