Maximize your Design ROI with Marker Interfaces and JavaDoc
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:
- 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.
- 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.