ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Design Markers
Explicit Programming for the Rest of Us

by Bruce Wallace
03/26/2003

Many choices made at software design time cannot be directly expressed in today's implementation languages like C# and Java. These design choices (known by names like Design Patterns, Design Contracts, Refactorings, Effective Programming Idioms, Blueprints, etc.) must be implemented via programming and naming conventions, because they go beyond the built-in functionality of production programming languages. The consequences of this limitation conspire over time to erode design investments as well as to promote a false segregation between the designer and implementer mindsets.

Two recent independent proposals recognized these problems and gave the same basic strategies for tackling them. Until now, the budding Explicit Programming movement has been linked to the use of an experimental Java research tool called ELIDE. The proposed Design Markers technique requires only standard Java and JavaDoc. For those who must restrict themselves to production-ready tools, this article describes how to use Design Markers, today, to provide many of the benefits of Explicit Programming.

Explicit Programming vs. Design Markers

Frankly, when I coined the terms Design Markers and Design Choices in the original Design Markers proposal, I had not yet heard of Explicit Programming and only later chanced upon its manifesto on the Web. It was immediately obvious that both shared a strategy of coining a name for each design choice and explicitly referencing those names in program source code. The second leg of the strategy was to embed the description of how to implement each design choice in the source. Each "how-to" description is factored out to a well-known place in the code. The coined name is the link between the many places in the code that reflect a particular design choice and its single implementation description. ELIDE calls these coined names modifiers and Design Markers calls them, well ... design markers.

The significant difference between the two proposals is in the mechanism used to implement these modular "how-to" descriptions. Design Markers have plain language descriptions that inform human programmers how to implement each choice manually (in other words, documentation). ELIDE automates the generation of code to implement design choices, defining Java language extensions that describe design choice implementations. (Think of a cross between macro preprocessing and aspect-oriented programming.) The tradeoff is implementation automation versus the use of (1) a still-evolving research tool (ELIDE), (2) its still-evolving language syntax, and (3) meta-programming (which requires different skills than normal programming).

There are also some finer-grained differences between ELIDE and Design Markers with regard to what kinds of design contracts can be defined. Design Markers (being Java interfaces) are only attached to classes and interfaces. ELIDE can attach modifiers to methods and even variables. On the other hand, ELIDE's contracts are not inherited by subclasses. It requires more work to enforce a consistent "is-a" relationship between classes and their subclasses. Design Markers are inherited.

However, the important benefits the two proposals still share are (1) preventing code from drifting away from its required design contracts, and (2) providing a trigger for design refactoring as code changes over time. These benefits are possible by keeping vital descriptions in the source code, where developers are more likely to see them and more likely to keep them synchronized than information kept in a separate design document. Items placed explicitly in implementation source code include:

  • A standardized vocabulary (of your choosing) with regard to design choices (be they well-known or newly-hatched concepts).
  • A design choice vocabulary that can mirror any custom UML stereotypes defined for a system.
  • Which design contracts are required (and where).
  • How a design contract should be implemented (especially when the details affect scattered points in the code).
  • Higher-level design contracts that can be defined in terms of lower-level contracts.
  • Why each design contract is being used (e.g., which tradeoffs between competing design patterns were chosen).
  • Design choices that can be prescribed at design time in a concrete form and carried intact into implementation.
  • Newly-evolved design patterns (which can be embraced in increments of your choosing).
  • Multiple design contracts associated with a single class or interface, if needed.

Related Reading

Java Enterprise Best Practices
By The O'Reilly Java Authors

What are Design Markers?

Design Markers are Marker Interfaces that are used primarily for documentation purposes--specifically to document Design Choices. The description of each design choice is placed in the JavaDoc comments of its associated marker interface in as much detail as desired. Design Markers (like all Java interfaces) cause JavaDoc to generate hyperlinks back and forth between each marker definition and the definitions of each of its heirs. Thus, it's trivial to navigate between the uses of a design concept and its definition.

I've coined the term Design Choices to encompass all flavors of design contracts because it emphasizes an oft-forgotten fact that design is not a checklist of "best practices," but rather an interacting set of choices. These choices balance tradeoffs between competing design patterns that are made for the benefit of an entire system rather than isolated classes. These global tradeoffs are often lost or forgotten when developers are in the heat of refactoring particular classes.

Marker Interfaces have no details, only names. This idea has long been used in Java via standard interfaces like Serializable, Clonable, RandomAccess, etc. However, their use has typically been limited to those interfaces intended for explicit, runtime verification (normally via instanceof).

Design Markers, though focused on documentation, share the root purpose of marker interfaces; namely, to declare adherence to a design contract that cannot be policed by the language compiler and runtime system. For example, just because a class declares that it "implements Serializable" doesn't mean that it has correctly implemented the Serializable contract. Since Java can't really tell if the contract has been met, using the marker interface is more of an explicit pledge by the programmer that it has. The overlooked benefit of marker interfaces is that they also document the intention that a contract should be met. Generalizing this notion to any design choice, Design Markers document the required obligations of a class and the reasons why.

For example, consider Data Transfer Objects (DTOs) that are passed as EJB remote method parameters. Since these parameters are passed as copies rather than Java's normal pass-by-reference, it is common to make them "immutable." Since one can't simply declare class Foo to be immutable in Java, a series of conventions must be programmed manually. With a design marker, the requirement that a class should be immutable is a simple declaration (e.g. class Foo implements Immutable).

Since interfaces in Java can inherit multiple parent interfaces, Design Markers benefit from being able to define higher-level contracts in terms of lower-level ones. So, to extend the above example, suppose for EJB method return values an extra restriction is desired to prevent counterfeits. One could coin the term "consume-only" to mean "classes whose instances can be read but not created by the user." A ConsumeOnly design marker interface documents that concept. Further, to codify the entire collection of contracts associated with return values, one could declare "interface ReturnValue extends ConsumeOnly, Immutable," thus documenting both a new contract and its relation to other contracts. The JavaDoc for each design marker interface can document its definition, how it needs to be implemented, and why it is done. Instead of copying this information into the comments of each return value class (or leaving it undocumented altogether), each need only declare "implements ReturnValue."

As a best practice, I recommend making all design marker interfaces an extension of a single root level design marker (e.g., "interface Immutable extends Contract"). This has two benefits: (1) making a place to document the project's practice of using Design Markers overall, and, (2) making it trivial, via JavaDoc, to get a hyperlinked catalog of all of your defined contracts. New project members will love you.

Are Design Markers Alone Worth the Effort?

Because programmers must use manually-enforced programming conventions to implement design choices, they naturally need to be cognizant of those design choices. However, without expensive round-trip design tools or experimental research tools, "the blueprints" are not typically at hand.

As programmers refactor, they can make changes that are locally appropriate but globally inappropriate. Worse, the consequences of breaking a design contract may be not be a functionality failure, but instead a performance failure. Since unit tests focus on testing functionality much more than performance, these defects may not be discovered. In addition, even changes that improve the performance of an individual unit may, in fact, hurt the performance of the entire system. This regression is even less likely to be caught if system-level tests are run less frequently than unit tests. Preventing breaks is much better than trying to catch them later via testing. Having design markers not only makes developers aware of pre-existing contracts, but provides a good trigger for design and/or code reviews. After all, changing a class' design markers is literally the same thing as changing its published interface.

O'Reilly Emerging Technology Conference.

Why haven't design choices traditionally been recorded in source code? Mostly, because there has been no clear place to put them. Even if each "typesafe enumeration" class had a comment noting that it followed that pattern, any elaboration (much less tutorial information) would not have been added because one either had to copy it repeatedly, or worse, place it sporadically in arbitrary spots. When creating the JavaDoc comments attached to each Design Marker interface, one can put in more detail than is typical because the comments do not need to be repeated anywhere else. Design Markers define a well-known place to factor out all of those details and encourage including design documentation. JavaDoc automatically publishes this data in a form that makes it trivial to navigate from each use of a design pattern to that pattern's central documentation, and vice versa. This is especially useful for project-specific, lesser-known, or newly-hatched patterns, idioms, conventions, et cetera.

Instead of creating actual marker interfaces, one might be tempted to invent and use custom JavaDoc tags (e.g., @Immutable, or @ThreadSafe). The new JDK 1.4 version of JavaDoc seemingly encourages this approach, as it allows simple command-line parameters to make JavaDoc aware of invented tags. However, Design Markers have these advantages over custom JavaDoc tags:

  • Design Markers have no start-up costs, unlike custom Doclet plug-ins that you would have to program for fancier processing than vanilla JavaDoc provides.
  • Marker interfaces are automatically inherited and therefore automatically referenced on all subclasses, so JavaDoc provides hyperlinks to all documented requirements. JavaDoc custom tags aren't inherited.
  • JavaDoc creates hyperlinks to and from each class and its inherited interfaces. JavaDoc custom tags generate only simple text, not hyperlinks.
  • Custom JavaDoc tags require JDK 1.4 (and therefore Ant 1.5) and special JavaDoc command-line parameters to declare them. Design Markers require no special version of JavaDoc (or any other tool) and no special command-line parameters.
  • While meant for documentation, Design Markers also allow test suites to verify design compliance by testing for the markers at runtime via instanceof. Tests cannot verify JavaDoc custom tags.

Conclusion

According to its charter, Explicit Programming intends for its tools to be "widely accessible to programmers" and not "require a developer to understand language parsing to be able to define grammar extensions." It also states that "ELIDE tries to provide less power [relative to other techniques] with the intent of remaining more accessible to programmers." These tradeoffs are the same ones that Design Markers make relative to ELIDE itself. Design Markers represent a technique that occupies the optimal decision point between embracing the Explicit Programming style and only requiring tools and techniques available to all Java programmers today.

Over time, as tools like ELIDE solidify and become production-ready, the design choices documented today by Design Markers will be ready and waiting to be converted to their use.

Examples

As a simple example of using Design Markers and illustrating the JavaDoc produced for them, the Java source files, and all of the JavaDoc generated for them, are available for viewing. Whether with JDK 1.3 or 1.4, the JavaDoc command used was simply javadoc *.java.

References

Bruce Wallace is principal consultant of PolyGlot, Inc.


Return to ONJava.com.