We say ``Never build an application.”
“But,” you may reply, “isn’t that what application programming is all about?”
“Yes.” We smile irritatingly. “But it shouldn’t be.”
What do we mean by this?
The first problem lies in building an application slavishly to fixed, rigid requirements.
Given the fluid nature of the user’s requirements and the rapidly changing face of business requirements in today’s market, it is foolish to try to build the application that you originally set out to build! By the time the project is complete, the needs will have changed. You will have built a legacy application right from the start, that needs to be ripped up and re-engineered to reflect not only the changes to the business world, but also to reflect the wisdom garnered by the staff during code development.
Now some folks will say, “ah, but we use an iterative development process so we can track the changing requirements as they happen!”. Well, not really. The team is still focused on building an application, perhaps one with a slightly shifting set of features, but any larger changes to work flow or capabilities is as likely as not to run aground.
A short digression: Some people misinterpret iterative development to mean the same thing as a waterfall-style development (analysis -> design -> code -> test) but with a much shorter cycle time. They miss an important point; the activities involved are peer functions, and you may freely bop between coding, analysis, design, test, etc. in any order in a non-linear fashion. These folks will often insist on a finalized design document before coding begins, ignoring the valuable feedback path from coding that influences design (and even analysis).
But even with a proper iterative development environment, the focus is mainly on developing an application, and I maintain that this is the wrong goal. So if you shouldn’t build an application, what should you build?
Rather than designing an application to serve a limited, fixed set of needs, look at a broader picture of the solution domain you are working in.
There’s an old Bell Labs proverb (cited in [C++]), that says:
Library design is language design.
That is to say, if you are designing a library of reusable functions to be called in varying circumstances, what you are really designing is a small, consistent “language” specific to the problem domain at hand. With a small library of functions, and a knowledge of the semantics of calling and combining the functions provided, the programmer can tackle any number of application-specific tasks that the library writer would never have been aware of.
This is a fine idea for well-defined, specialized tasks like matrix operations, statistics, 3D graphics, etc., but how does this idea of a rich function library translate into the guts of an object oriented application?
A true object oriented program is designed without a “top” ([OOSC2]), that is, without a well-defined single high level “here’s how the whole thing works”. What the user sees as an application program is but one particular entry point that invokes the objects necessary for the application. This now implies that what the user perceives as the application could be dramatically altered by augmenting and combining the available objects in a different way.
So ideally then, what the designer of a project should bear in mind is the following goal:
Design a domain specific “language” that can be used to talk about applications in this domain.
Note that applications is plural!
This “language” may take shape in the form of:
- Services that classes of objects can provide.
- Interactions between objects to fulfill promised services.
- Definition of meta-data to describe the data that the system will operate on.
and all the other usual tricks that make up an implementation.
Hasn’t this been said before?
As an aside: nothing really is new; Plato and Aristotle spoke of classes of objects, taxonomies and such. The ancient Greeks named the atom long before we had nuclear subs. Even the Bible described communications using a binary notation ([MATT])! Nothing really NEW has been invented for several thousand years, actually. Improved a great deal, but not quite as new as we’d like to think.
So how do these ideas relate to the current hot topics and buzzwords in our industry?
The current rage with the UML focuses a great deal on class modeling. A fine notion, but beware of the fine print. Modeling the actual classes that will be implemented (via code generation/round trip engineering) is obviously an implementation level activity. By this time, the horse is out of the barn and halfway down the road. Conceptually, what you want to model is this domain-specific “language” space, and keep that in sync with the users. This may of course have multiple valid implementations (which kills the notion of reversibility, but that’s a separate matter). I think this is different from those involved in domain modeling per se, as we intend to model a sufficiently rich solution space, not the problem domain itself.
Reusability is one of the more popular buzzwords of the day, and is a fine goal if you need the code base to span multiple projects, or across an entire enterprise. But first things first: usability must happen before re-usability. Some validation and testing might be a rare thrill as well. Reusability is a two-edged sword; do not waste time adding flexibility that isn’t needed, neither limit yourself from adding such flexibility in the future. It’s a fine line, and quite a tricky thing to get right. But it can help to NOT think in terms of reusability, but rather flexibility and expandability to achieve the same goal.
[C++] Stroustrup, Bjarne. “The C++Programming Language” Addison-Wesley, 1991.
[OOSC2] Meyer, B. “Object-Oriented Software Construction, Second Edition” Prentice Hall, 1997.
[MATT] King James Bible, Matthew 5:37: “But let your communication be, Yea, yea; Nay, nay: for whatsoever is more than these cometh of evil.”