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.
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:
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
RandomAccess, etc. However, their use has
typically been limited to those interfaces intended for explicit, runtime
verification (normally via
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 "
doesn't mean that it has correctly implemented the
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
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 "
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
As a best practice, I recommend making all design marker interfaces an
extension of a single root level design marker (e.g., "
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.
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.
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.,
@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:
instanceof. Tests cannot verify JavaDoc custom tags.
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.
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
Bruce Wallace is principal consultant of PolyGlot, Inc.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.