Patterns and Software Development

If we're ever to realize the promise of object-oriented programming, we first have to be able to create and package truly reusable software components--and "patterns" may be the way to do it. Kent examines one of the hottest topics in software development.


February 01, 1994
URL:http://www.drdobbs.com/mobile/patterns-and-software-development/184409176

FEB94: Patterns and Software Development

Kent is founder of First-Class Software, providing consulting, tools, and components for Smalltalk developers. He can be reached on CompuServe at 70761,1216.


Patterns are a way of developing and packaging reusable software components. The idea of patterns is gaining attention in certain programming circles--especially those based on object-oriented languages and paradigms. At last fall's OOPSLA '93 conference, the foreground topics focused on mainstream development methodologies (such as the second-generation versions of Booch, Rumbaugh, Shlaer-Mellor, and the like), but smoldering in the background was much discussion around patterns. This subject will likely catch fire in the coming year.

Driving the discussion of patterns is the ongoing need to create truly reusable software--the long-awaited benefit of OO languages and methodologies that has yet to materialize.

In this article, I'll look at patterns as a method of guiding reuse. Although some of this discussion may be abstract, it draws upon my ten years of experience as a programmer and current vendor of object tools (Profile/V and the Object Explorer).

Patterns should not be confused with methodologies. A methodology tells you how to write down the decisions you have made. A pattern tells you which decisions to make, when and how to make them, and why they are the right decisions. Methodologies are free of content: Once you imagine a specific solution to a problem, a methodology gives you the wherewithal for writing it down and arriving at a correct implementation. By contrast, patterns are all content.

Abstractors and Elaborators

I divide the world of software development into two parts: the abstractor, creating reusable pieces; and the elaborator, massaging those pieces to fit the needs of a user. Microsoft has lately been promulgating a roughly similar vision, in which software development is divided into two categories: component builders (for example, programmers who write a DLLs or class libraries in C or C++), and solution builders (those who use high-level tools such as Parts, Visual Basic, PowerBuilder, or an application framework in conjunction with low-level DLL components to construct application-level solutions for end users). The abstractor/elaborator categorization is more general, so I'll stick with it.

The economics of reusable software are dominated by the cost of communicating between abstractor and elaborator. For example, if an abstractor takes 1000 hours to create a piece of reusable software, and 100 elaborators each take 100 hours to understand how to use it, then the elaborators have collectively spent ten times as many hours as the abstractor. Obviously, these numbers are hypothetical, but six months to create a reusable component and two-and-a-half weeks to learn how to use to use it effectively are well within the realm of possibility.

Making the abstractor more efficient (by providing, say, a faster compiler or whizzy debugger) won't reduce the total effort spent on writing software; if you view the abstractor and the elaborators as belonging to the same economic domain (say, a large corporation or organization), the equation's total is little changed. The only way to significantly affect the sum is to either reduce the number of elaborators (a bad thing, because it implies that software is not being reused, and thus more work is done from scratch), or reduce the time they spend figuring out the software.

This is nothing new. The old story of maintenance taking up 70 percent of the resources is really another way of saying the same thing. The new wrinkle is that, when you introduce software reuse into the equation, it isn't just one hapless programmer trying to figure out an obscure piece of code--it's hundreds.

Constructing a software component so that it is reusable is a step forward, but nowadays it's not enough. The abstractor needs to do more. Why should the abstractor care? In one model of reuse, there is a development team within a company building software components for other teams to use; in this model, making the elaborators more efficient reduces the development resources required. The company can then use the freed-up resources to shorten time-to-market, increase features, reduce development cost, or improve quality.

In another model of software reuse (the market model), reusable components are available for developers on the open market (for example, the Visual Basic add-on market). Here, if you are a VBX vendor (abstractor) and your customers (elaborators) are able to produce finished applications sooner, you will have a substantial edge over your competition.

If the time it takes elaborators to figure out reusable software is an important issue and solving the problem has significant payback, how can we reduce the time necessary to understand how to reuse software? What is it that, in the hands of elaborators, would make them more successful, sooner? Another way of asking the question is, what do abstractors know that they aren't communicating?

What's missing is a way for abstractors to communicate their intent. The abstractor, in building a piece of reusable software, is solving a whole set of future problems. Indeed, most reusable software results from the experience of being an elaborator several times, then having a flash of insight that solves a number of elaborator problems once and for all. The abstractor needs to communicate which problems a reusable component is intended to solve, how to think about the problem, how this thought process is embodied in the software, in what order to pursue subissues of the problem, and so on. Communicating with elaborators is more important than, say, using a better programming environment.

If you need to communicate what you were thinking about when you wrote your reusable software, what form would such communication take? Of course there are the usual mechanisms--a tutorial, reference manual, comments in the code, the coding conventions used by the source (if it is available to the elaborator), and, of course, word of mouth--bits of advice passed from guru to novice.

Researchers and developers have been exploring another approach, which falls under the rubric of patterns. I'll discuss the abstract definition later; first, I'll provide a concrete example of how patterns can be used to communicate the programmer's intent.

A Multicurrency Library

Let's take as an example a class library for handling multicurrency transactions. There are two principal classes: a Money entity, which has a value and a currency, and a CurrencyExchange, which can convert a Money in one currency to a Money in another. How can you use these objects? What is the intent behind the design? Here are three patterns that describe it. While by no means complete, a set of 15 or 20 such patterns would provide any elaborator a good start on reusing the library.

The Money Object Pattern

Problem: How to represent a monetary value in a system which needs to deal with many different currencies.

Constraints: One important concern in a system dealing with financial calculations is efficiency--making sure the calculations run in a timely manner and use as little memory as possible. The simplest representation of monetary values, and one which maps well onto the hardware, is representing them as fixed or floating-point numbers.

While you'd like your system to be as efficient as possible, you'd also like it to be flexible. For instance, you'd like to be able to decide as late as possible in which precision computations should occur. The rapidity of change of most financial systems dictates that flexibility is more important than efficiency for most applications---you can always buy faster hardware. When you need real number crunching, you can translate from and to a representation more flexible than simple numbers.

Another consideration, related to flexibility, is that a system handling multiple currencies should be as simple to use as possible. Only code concerned with creating or printing currency values should be aware that many currencies are possible. The rest of the code should look as much as possible like you are just using numbers.

Solution: When you need to represent a monetary value, create an instance of Money whose value is the value you need to represent and whose currency is the standard, three-character abbreviation (USD for United States dollars, for instance).

The Money Arithmetic Pattern

Problem: How can you do arithmetic with Money?

Constraints: Money arithmetic should be as simple as possible. Taking this constraint to the extreme would lead you to allow Money and numbers to freely interoperate, perhaps with a default currency to allow conversion of numbers to Money.

A far more important principle than mere programming convenience is making sure financial algorithms are correct. Restricting the combinations of values that can operate together arithmetically can catch many programming errors which might otherwise produce answers that seem reasonable, but are incorrect.

Solution: Send a Money the message + or -- with another Money as the parameter, or * or / with a number as the parameter. A Money will be the result of any of these messages. Adding a Money and a number, or multiplying two Moneys will result in an error.

The Money Print Pattern

Problem: How can you print a Money?

Constraints: The simplest possible design has a single global exchange rate. Asking a Money to print itself would cause it to convert to the common currency and print.

This simplest solution ignores the complexity of most financial systems, which must deal with multiple exchange rates--some historical, some current (perhaps kept up-to-date with currency exchanges), some projected. By specifying an exchange rate (in the form of a CurrencyExchange), your printing code will be slightly more complicated, but much more flexible as a result.

Solution: Print Money by sending CurrencyExchange the message "print" with Money as an argument. Money will be printed in the CurrencyExchange's preferred currency. There is a second message, printCurrency, which takes two arguments. The first is the Money to be printed, and the second is the currency (again, a three-character string containing a standard abbreviation) in which to print it.

Patterns

As you can see, a pattern has three parts:

Patterns Form Language

Although patterns are interesting in isolation, it is when they work together, forming a coherent language, that their power becomes apparent. A few times in my life I've been fortunate enough to work with someone who just seems to ask the right questions first. Rather than chasing issues that seem interesting but are ultimately secondary, some people can zero in on the one issue at any given moment that will allow the most progress. A language of patterns can function in much the same way.

By choosing the order in which the patterns are considered, the pattern writer has the chance to guide the reader in dealing with issues in the right order. In the patterns above, I have chosen to ignore efficiency for the moment, confident that should the issue arise later, it can be dealt with locally (I can imagine a later pattern which tells how to temporarily suspend the flexibility of Money to gain efficiency). In general, a good pattern language will lead you to address issues with wide scope early, and those with limited impact later.

How can you write your own patterns? The bad news is that applying patterns to programming is a new enough technique that there isn't anything like a body of experience to draw on. However, the Hillside Group has made progress with patterns. (See the accompanying text box entitled, "Pattern Resources.")

The first step in writing a pattern is a process of discovery. You notice yourself making the same decision over and over. You might find yourself saying, "Oh, this is just a such and so," or, "Oh, we don't have to worry about that now." These are the moments that you can capture as patterns.

Once you have noticed a recurring decision, you have to invent the pattern that encodes it. First, you must catalog the constraints that make the solution right. You will often find in exploring the constraints that you don't quite have the solution right--either it isn't the right solution, or you've described it too specifically or too generally. Finally, you have to find a problem statement that will help a reader choose when the pattern is appropriate.

A Pattern Checklist

After you have a pattern, you need to evaluate and refine it. Here is my checklist when I'm looking at a new pattern:

Using patterns to enhance reuse is just one of the ways patterns are being applied to programming.

Pattern Resources

The idea of patterns capturing design expertise originated with the architect Christopher Alexander. His books The Timeless Way of Building and A Pattern Language (both from Oxford Press) are required reading for anyone who wants to get serious about patterns. A forthcoming Addison-Wesley book, Design Patterns: Micro-architectures for Object-Oriented Design, by Erich Gamma et al., catalogs some of the most common object patterns.

The Hillside Group is a nonprofit corporation founded to promote communication to and through computers by all potential users, focusing initially on patterns as a strategy. The founding members are myself, Ken Auer, Grady Booch, Jim Coplien, Ralph Johnson, Hal Hildebrand, and Ward Cunningham. Our sponsors are Rational and the Object Management Group. In August 1994 we will sponsor the first annual Pattern Languages of Programs conference. For more information, contact [email protected]. The Hillside Group also has a mailing list, which you can contact at [email protected].

--K.B.


Copyright © 1994, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.