<<Title>>
Design
Markers
Maximize
your Design ROI with Marker Interfaces and JavaDoc
Bruce
Wallace
President,
PolyGlot, Inc.
http://www.PolyGlotInc.com/
bruce.wallace@acm.org
There are many
choices made at design time which cannot be directly expressed in
implementation languages like Java, C/C++/C#, etc. These choices (which are
known by names like Design Patterns, Design Contracts, Refactorings, Effective
Programming Idioms, Blueprints, etc.) must be implemented via programming &
naming conventions because they go beyond the built-in functionality of typical
programming languages.
As will be shown, two consequences of this limitation
conspire to erode your wise investment in design. They also promote a false
segregation between a designer mindset and an implementer mindset. While contemporary solutions to the
problem range from expensive proprietary design tools to a disavowal of overt
design and documentation altogether, the overlooked technique detailed herein
is simple, portable, and essentially free. It can be used with a development environment as humble as a
text editor and a web browser.
The author has coined the term Design Markers
to label the technique shown that leverages un-extended JavaDoc with Marker
Interfaces to tie the “what” and “how” of the code to the “why”. This method
bridges the gap between the philosophies of Self-Documenting-Code (aka
Undocumented-Code) and Literate Programming. It not only helps to insure that
design choices are not forgotten at implementation and maintenance time, but
also encourages developers to preserve a coherent design as the system evolves.
Compared with JavaDoc’s new custom tags, design markers are simpler, and, they
produce superior results without the need for special Doclet programming.
There
is a book surveying Java tools for extreme programming that left out, in my
mind, one of the most fitting tools: JavaDoc. I suppose, like the proverbial
girl next door, though right under our noses, it goes unappreciated. The concept of Design Markers is also
deceptively simple and, at first glance, even the author did not anticipate
several of the practical benefits of their use. So, after defining Design
Markers, a discussion of these benefits will be presented.
What are Design Markers?
Design
Markers are Marker Interfaces that are used primarily for documentation
purposes and specifically to document Design Choices. The description of each design choice
is placed in the JavaDoc comments of its associated design marker interface in
as much detail as desired.
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.
Marker Interfaces are defined as those that have no
details, only a name. 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 to be explicitly
verified at runtime, normally via “instanceof“.
Design Markers, even though focused on documentation,
share the root purpose of marker interfaces; namely, to declare adherence to a
design contract whose implementation cannot be policed by the language compiler
and runtime system. For example,
just because a class declares “implements Serializable” doesn’t mean that it has correctly implemented the
Serializable contract, but 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. An alternative notion that the source code alone
can/should be the documentation has two problems here:
(1) If the implementation of a contract
(even a well-known one) is more complicated than a few simple assert
statements, it is easy to not recognize that a contract is being implemented at
all, much less which one.
(2) Even when a contract can be
inferred from the implementation source, it is not clear why that
contract is being implemented. In
other words, was a class made Serializable just because the programmer felt
like it, or is it a requirement of some encompassing system design?
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.
For example, a “Singleton” design marker can be created to mark classes
that are to implement that well-known design pattern. Additionally, Sun’s J2EE
pattern, “Service Locator”, which usually requires that the Service Locator be
a singleton, can be enshrined as a design marker that inherits the Singleton
marker interface. Thus, any class
marked as a ServiceLocator is automatically documented as needing to be a
Singleton. So, not only has the fact that a class must be a singleton been
established, but also the reason why.
When creating the JavaDoc comments attached to each
interface, one can put more detail than typical because the comments do not
need to be repeated anywhere else.
Traditionally, even if each singleton class had a comment noting
that it was a singleton, any elaboration (much less tutorial information) would
not have been added because it would have needed to be copied repeatedly (or
worse, it would have been placed sporadically in arbitrary spots). Design Markers define a well-known
place to factor out all those details and encourage including design
documentation. JavaDoc automatically publishes all this 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 or lesser known or newly hatched
patterns, idioms, conventions, etc.
For example, consider Data Transfer Objects (DTOs)
that are passed as EJB remote method parameters. Since copies of these parameters are passed, 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.
However, with a design marker, the intention that a class should
be immutable is a simple declaration (e.g. class Foo implements
Immutable). Even if a
pattern is well known, particular variants could be specified. For example, the
design marker’s JavaDoc comments could explain: “a variation is being used
where no “get” methods are defined since users can safely access the property
fields directly because each must be declared public and final”.
To extend the example, suppose for EJB method return
values, an extra restriction was desired to prevent counterfeits. One could
coin the term “consume-only” to mean “classes whose instances can be read-by
but not created-by the user”. A ConsumeOnly design marker interface is created to document 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,
why it is done, etc. And instead of redundantly copying this info into the
comments of each return value DTO class (or leaving it undocumented
altogether), each need only declare, “implements ReturnValue”.
Since markers are like little sticky notes attached
to individual classes, they work well for “adjective patterns” like Immutable,
Serializable, Singleton, etc. However, relationships between multiple classes
can still be documented by defining each of the roles in that relationship as
Design Markers. The roles could even inherit a master marker for the overall
pattern. For example, the MVC
pattern defines three roles (Model, View, & Controller), and each can be
defined as a Design Marker. Each could also inherit an MVC marker in which to
place documentation about the pattern as a whole and the relationships between
its roles.
Finally, as a “best practice”, I suggest making all
design marker interfaces an extension of a root level design marker (e.g. 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 your defined contracts. New
project members will love you.
How do Design Markers compare to other methods for
the problems they solve?
Today, design and implementation are expressed in
different languages, and this is the root problem that Design Markers attack.
While implementation is embodied in artifacts like source code, build scripts,
and configuration files, design is kept in artifacts like UML diagrams, design
models, or even primitive word processor documents. Because they can’t express
design choices directly in their implementation languages, implementers must
use manually enforced programming conventions, and so naturally, they need to
always be cognizant of those design choices. However, without an expensive round-trip
design tool, “the blueprints” are not typically at hand (or even kept up to
date). Because design choices are spillage in the shuffle between design and
implementation, developers are often unaware of them and therefore fail to
maintain them. The problem only gets worse over time as development mode turns
into maintenance mode, often with personnel turnover. Finally, since this problem is just a special case of the
general problem of human communications, its severity grows rapidly with
project size.
So, design choices go
unknown by the harried new hire bug fixer. The self-assured experienced
developer who is mightily refactoring code is not reminded of why his seemingly
more optimal version of a class, never the less, breaks the overall system. Moreover,
while testing might discover broken contracts after the fact, it is much better
to prevent them. Good programming practice says that things requiring
synchronization should be proximate to each other in the source code. There is nothing in more need of
synchronization than “what the design decrees” and “how and where the
implementation fulfills it”.
A special mention
must be made about the problems associated with refactoring in the absence of
design markers. Often programmers
“clean up code” while adding a new feature or fixing a bug, even though they
were never “briefed” on the design choices governing that code. Even those who were
briefed don’t have perfect memories. Reasonable programmers will make locally
appropriate, but globally inappropriate, changes when they are not conscious of
the tradeoffs made for the good of the entire system. 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. And this regression is even less likely
to be caught because system level tests (like integration and acceptance tests)
are done much less than unit tests. Again, 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 a design and/or code review, namely, the changing of a design marker (i.e.
a contract) which, after all, is literally the same as changing the published
interface.
So, why aren’t design choices recorded in source code
more often? Mostly, because there has been no clear place to put them. The extant choices are (1) simple
comments, (2) custom JavaDoc tag comments, and (3) proprietary markup added by
round-trip design tools. If you have the budget for fancy tools and their
associated developer training, more power to you. If not, or if you want to use
a more portable mechanism, there are comments. However, comments, whether plain
or in JavaDoc tag form, do not provide the Design Marker benefits discussed
ahead.
A variation on simple comments is to invent and use
custom JavaDoc tags (e.g. @Immutable, or @TypeSafeEnum). This approach is given more
encouragement with the new JDK 1.4 version of JavaDoc that allows simple
command line parameters to make JavaDoc aware of your invented tags and produce
"official" documentation in the generated HTML. However, the HTML
generated by JavaDoc is still just text (albeit with nicer paragraph
headers). A Design Marker (like
all Java Interfaces) causes JavaDoc to generate hyperlinks back and forth
between its definition and the definitions of each of its heirs. While
arbitrarily elaborate processing of your custom JavaDoc tags can be had if you
learn the Doclet framework & API, and write custom Doclet plug-ins, this
option does require tool development time, and therefore, money.
A summary of benefits of Design Markers over JavaDoc
tags follows:
As a simple example of using Design Markers and illustrating the JavaDoc produced for them, I have placed four Java source files (Abelian.java, AddrType.java, Contract.java, and TypeSafeEnum.java) and all the JavaDoc that is generated for them (starting with index.html) at http://www.polyglotinc.com/designMarkerExample/ and they can be viewed and/or downloaded from there. Whether with JDK 1.3 or 1.4, the JavaDoc command that was used is simply “javadoc *.java”.
As principal consultant of
PolyGlot, Inc., Bruce Wallace has provided consulting and custom computer
software development services around the world. Projects have been completed in
Sydney Australia, Perth West Australia, "Silicon Valley" California,
"Route 128" Massachusetts, Austin Texas, and currently in Atlanta
Georgia. Bruce has been developing with Java since 1996, Object Orientation
since 1988, and Software Engineering since 1974. During his career, he has
covered the full spectrum of roles from manual QA tester through CTO, even in
organizations you’ve heard of like Apple Computer, Sun-Javasoft,
Hewlett-Packard, Coca-Cola, and BellSouth. Bruce’s first published article was
way back in the May 1981 issue of Byte magazine, and his most recent was in the
March 2001 issue of JavaPro magazine [http://www.polyglotinc.com/reflection.html].
<<Copyright>>
Copyright, 2002-2003, PolyGlot, Inc.