Hugh Winkler holding forth on computing and the Web

Wednesday, February 08, 2006

Patterns: Another Way To Say "Bloat"

A quote I'd missed at the very end of this oft-linked Paul Graham essay:
...in the OO world you hear a good deal about "patterns". I wonder if these patterns are not sometimes evidence of case (c), the human compiler, at work. When I see patterns in my programs, I consider it a sign of trouble.


It's elementary information theory, sir. Any pattern, or predictable part, of the signal is non-informative bit bloat. Compression programs work by identifying predictable patterns and encoding them simply: if the pattern recurs, you don't have to repeat it verbatim. You can just say, e.g. "Pattern 3 again" to substitute for the longer sequence.

It's the same with programming. Coding patterns is cut and paste. Eclipse will even help you do it, in Java; it has all sorts of nifty shortcut keys to do patterns like "return an array from a collection instance." That's reverse compression: You type Ctrl-Shift-J or whatever, and Eclipse expands it into the pattern for you.

Here's a pattern that gripes me in java: for data access, I usually make two methods for each thing I want to access. Both methods accept all the parameters you need to select the thing; but one method accepts a JDBC connection parameter, while the other constructs and destroys the connection and calls into the first method. The second method is a convenience procedure, while the first one allows you to make the call as part of a series of actions withing the same transaction. You know...


public static long getMetainfoId(UID uid, String objectType){
try {
// notice the pattern within a pattern below (service locator)
Connection conn = ServiceLocator.getInstance().getDataSource().getConnection();

try {
return getMetainfoId(conn, uid, objectType);
} finally{
conn.close();
}

} catch (Exception e) {
throw new RuntimeException(e);
} finally {

}

}

public static long getMetainfoId(Connection conn, UID uid, String objectType){
.... do the real work
}


I have cut and paste that snippet about five hundred times.

I want a way to avoid both compile time and run time bloat. I don't just want a magic macro that saves source code; I want the actual wrapper code to be generic. I asked my friend and colleague Brad to sketch a Lisp solution:

the wrapper function would be something like this:

(defun wrapper (resource-creator resource-usinge-function &rest args)
"resource creator is a function that creates the resource we will
temporarily use. We can also parameterize it if necessary at compile
or run time using lambdas depending upon needs"
(let ((resource (funcall resource-creator)))
(unwind-protect
(apply resource-using-function resource args)
(resource-close resource)))) ; resource close could be a generic
function or parameterized as well


when defining a wrappapble function:

(define-wrapped get-uid (connection metainfold)
(create-connection p1 p1) ; this line specifies the resource creation function
(your code here)) ; the body that does the work and gets wrapped


I'm going to learn Lisp!

No comments: