After my initial attempt at doing something useful and automated around design patterns, I started working again on a brand new version of a pattern-aware tool: Patternity.
No more code generation, the focus is now on the generation of documentation artifacts (UML class and sequence diagrams, reports, enhanced Javadoc…) from the source code annotated with explicit pattern occurrences declarations. More like a research project, the goal is to investigate how a tool can be valuable for developers by being aware of the pattern and their occurrences in the source code.
Unlike the initial tool I did in 2002 that was really basic, there are many challenges and concerns to be addressed for a tool to deal with pattern in a clever way:
- Patterns variants: a pattern can be realized in the source code in many different ways, while still being the same pattern. For instance many patterns rely on polymorphism,which in practice can be achieved with an interface, an abstract class or just a non-final class. Many patterns also use some form of delegation, typically through an association (member field), but the pattern still holds if the delegation occurs through a lookup mechanism.
- Representation of patterns: creating a patterns database of a priori knowledge about patterns, including their static and dynamic aspects in a formal way that a tool can interpret – for instance to generate diagrams. Such representation must also be small enough to be feasible manually (of course only once).
- How to declare patterns occurrences within the code without interfering with the developer flow of work: easy and logical annotation syntax, good defaults values, code completion in IDE.
- How to generate useful artifacts: documentation class and sequence diagrams, reports…
An analysis of a pattern metamodel (points 1 and 2 above) reveals other concerns that add up to the task:
- Occurrences: What is a pattern occurrence in the code? How many occurrences of the same pattern can be considered the same occurrence? It sounds obvious that a Strategy class and all its subclasses are indeed one same pattern occurrence, but this is a priori not true for the subclasses of an Immutable class (I take a very wide definition of patterns that includes many idioms and other UML-like stereotypes).
- Classification: Patterns usually couple a Problem (or Intent) and a Solution for it within a Context; how to create the most useful classification of patterns? (I tend to favour a classification by Problem, but this means a SecurityProxy will probably not be related with a VirtualProxy, which is not very intuitive)
- Identification: How to identify a pattern occurrence? This is useful so that a declaration of a pattern occurrence can reference another pattern occurrence as a member part of it, just like the Bureaucracy pattern is composed of a Composite, a Mediator, a Chain of Responsibility and an Observer.
Declaration of pattern occurrences in the source code (point 3 above) also has its issues:
- Syntax: Definition of a good syntax, easy to grasp with as little explanation as possible is hard
- Consistency: many patterns introduce additional elements (we can call them active participants) around existing elements (passive elements) that must not know about the pattern. For instance in the Decorator pattern, the Decorator participant (role) participates actively in the pattern, whereas the decorated element should NOT be touched at all, which means that the source file for the decorated class should not be touched in the version control when adding the pattern.
- Where to declare: in the source code, using Javadoc tags for classes or methods, or in an external file when this is more convenient (e-g to annotate third-party libraries).
Generation of documentation artifacts
Generation of artifacts (point 4 above) from both the pattern occurrence declaration and the a priori knowledge about the pattern in the pattern database also yields its own challenges:
- Reuse, adapt or create a Java API to generate diagrams
- Find out a logic to interpret pattern data into diagrams or other reports
- How to deal with huge code bases: use ellipsis, continuation marks and move details to addendum to reduce the size of a diagram
Why use patterns for documentation?
Patterns can store pre-digested documentation as “templates”, either textual or visual (diagrams); then for each actual pattern occurrence these templates can be “evaluated” to generate real and complete documentation artifacts. When we want to create useful documentation, the need for developers to inject design information in addition to the information that is already present in the code base can therefore be reduced, since a significant part of these additional information can be factored out and stored once into the patterns metamodel. I expect that patterns are a convenient concept to encapsulate reusable design information and how it can be used, however this has still to be demonstrated in practical use.
I expect that patterns can help create better diagrams than usual case tools, just because patterns know more about the design: knowing that the Bridge pattern is made of type hierarchies (to render vertically) and a delegation betweem them (to render horizontally) makes it easy to draw its class diagram this way:
Possible validation of the utility of the tool can be:
- Design documentation reconstitution: on a well-known and well-documented Open-Source project in Java, annotate the source code with pattern occurrences declarations, then generate a documentation. By comparing this generated documentation with the official documentation of the project one can manually assert the relevance of our approach
- Maintenance experiments: similar to this study.
- From the sole pattern database, generate default documentation for each “default” (generated) pattern occurrence, and compare with the patterns books, the more similar the better.
We could imagine several other potential benefits from using a pattern-aware tool:
- The requirement to explicitly declare each pattern occurrence while coding also leads to a more motivated design, where each design decision has to be deliberate rather than more or less random or automatic. For beginners, this also represents an incitive to open the books more often to lookup “what is the pattern I am trying to do right now?” because of the need to document it.
- Provided that the tool can link a pattern with the Problem it is supposed to address, the pattern occurrences can then trace back to their Problem, and from there, link to other alternative patterns that could have been used as well. This could be valuable to do design-level refactoring.
- The explicit knowledge of the pattern occurrences in the code base can also give insight to configure other tools: for instance, since the patterns know what participant is supposed to know or not the other participants, this knowledge could be used to configure Jdepend automatically.
Please let me know your ideas, remarks or scepticism on this topic!
The official Patternity website still presents the old version; I expect to update it when there is good progress on the new version, however the new source code will be very soon under the same Sourceforge CVS.