Stagean annotations
Stagean is a Java library of annotation types that let you document development stage of your project on class or method level. Hand-edited Stagean annotations complement automated coverage and analysis tools to create overall picture of project's state and progress.
Example
In the example below, @NoDocs
, @DraftTests
,
and @StubCode
are development stage annotations.
They inform developers and users about development stages reached by this particular class and method.
@NoDocs @DraftTests("Async scenarios are untested.") public class MyClass { @StubCode public void doSomething() { throw new UnsupportedOperationException(); } // ... }
Download
Get Stagean from Maven Central:
<dependency> <groupId>com.machinezoo.stagean</groupId> <artifactId>stagean</artifactId> <version>1.3.0</version> </dependency>
Or clone sources from GitHub or Bitbucket. Don't forget to configure your build for Java 11+. Last version compatible with Java 8 was 1.0.2. Sources and binaries are distributed under Apache License 2.0.
If your project is a Java module,
add the following declaration to your module-info.java
:
requires com.machinezoo.stagean;
Available annotations
All annotations currently defined by Stagean are arranged in the table below.
Stagean recognizes four different development stages that can be assigned to four different content types.
Any development stage annotation can be clarified with one or more *Issue
annotations.
No* |
Stub* |
Draft* |
Complete* |
*Issue |
|
---|---|---|---|---|---|
*Api |
@NoApi |
@StubApi |
@DraftApi |
@CompleteApi |
@ApiIssue |
*Code |
@StubCode |
@DraftCode |
@CompleteCode |
@CodeIssue |
|
*Tests |
@NoTests |
@StubTests |
@DraftTests |
@CompleteTests |
@TestIssue |
*Docs |
@NoDocs |
@StubDocs |
@DraftDocs |
@CompleteDocs |
@DocIssue |
Annotation NoCode
does not exist, because it does not have any meaning.
Use @StubCode
instead.
Applications and libraries are free to define their own annotations,
but the annotations defined by Stagean are expected to have the best support in scanning and reporting tools.
How to track project progress
Common approaches that existed before Stagean:
- Mark whole project with overall development stage.
This is the well-known alpha/beta/... classification. This approach fails in projects that have stable core surrounded by experimental extensions, a very common scenario in opensource libraries. - Have separate experimental packages.
This causes breaking changes when classes mature and it doesn't work for experimental methods and nested classes. - Flag experimental code in Javadoc.
This often takes the form of a very visible "(EXPERIMENTAL)" banner in class summary. This is a very flexible solution, but it's informal, which hinders development of reporting tools. - Use coverage tools.
This works well for missing tests and docs, less so for ineffective tests and quick-n-dirty docs, and not at all for unstable APIs and incomplete implementations.
All of the above solutions still apply. Stagean just adds another tool to your toolbox:
- Add Stagean annotations.
Annotations capture developer's understanding of code quality. They are visible in code and in javadoc. Regex search will reliably find them. Tools can be developed to scan for them and create reports.
Development stages
Stagean recognizes four development stages:
@No*
Used when given type of content does not exist at all, e.g.@NoDocs
if there's no javadoc yet. This is perfectly unambiguous and the bare annotation without further comments is usually enough.@Stub*
Stub is a dummy placeholder. For example,@StubCode
indicates the implementation just throwsUnsupportedOperationException
or does something similarly trivial. The work is still 0% done, but@No*
annotation is not applicable, because something technically already exists. Stubs may contain some minimal content. For example,@StubDocs
javadoc would include the required summary sentence.@Draft*
Draft content needs more work. The annotation doesn't say how much. It could mean the work is 5% done or 95% done. Annotation's parameter or nearby comments should summarize what is unfinished.@Complete*
Indicates that this type of content is perfect, i.e. no changes are needed. The work is 100% done. There is a bit of ambiguity in what you consider "done", but generally it means you have no TODOs left.
@Draft*
stage is deliberately broad to minimize ambiguity and to avoid wasteful tinkering with annotations.
Some ambiguity might arise at its extremes with @Stub*
near 0% and with @Complete*
near 100%.
Criteria for @Stub*
and @Complete*
are somewhat project-specific.
If in doubt, use @Draft*
annotation.
// BAD: Abusing stub for working code. @StubCode("Switch to front crawl. Improve speed.") // DON'T DO THIS void swim() { // ... } // GOOD: Any non-placeholder implementation, even simple one, is a draft. @DraftCode("Switch to front crawl. Improve speed.") void swim() { // ... } // GOOD: Appropriate use of stub annotation for do-nothing implementation. @StubCode void swim() { logger.warn("Swimming is not implemented yet."); }
@Complete*
stage is the default when no annotation is present.
You can use it anyway for clarity, but the advantage of omitting it is that
Stagean annotations will add overhead only in unfinished code.
// BAD: If there are TODOs, it is not done yet. @CompleteCode("Just improve performance.") class MyClass { // ... } // OKAY: Redundant but technically correct. @CompleteCode class MyClass { // ... } // BEST: No need to annotate finished code. class MyClass { // ... }
Target content
Stagean currently supports flagging of these kinds of content:
@*Api
Applies to API, which usually means signature and behavior of public types and members.@*Code
Applies to implementation, i.e. everything behind the API.@*Tests
Applies to tests, usually unit tests. This annotation should be applied to code under test. It can be also informatively applied to test code itself, but scanning tools will likely ignore annotations on test code.@*Docs
Applies to javadoc and perhaps related external docs.
Comments
Development stage can be clarified with @*Issue
annotations
that describe concrete problems that need to be solved or steps that need to be taken to improve the code.
If there is not much to say, you can also use the free-form parameter accepted by all development stage annotations.
@Draft*
stage almost always needs clarification text, but all other development stage annotations can be commented too.
Longer descriptions can be wrapped in a multi-line string literal (Java 15+) and formatted in Markdown syntax. This is preferable over comment blocks, because annotation content can be displayed by tools.
// BAD: No information about what needs to be improved. @DraftCode class MyClass { // ... } // GOOD: Annotation's parameter lists remaining issues. @DraftCode("Add exception handling. Improve over O(N*N) complexity.") class MyClass { // ... } // GOOD: Brief summary, details in *Issue annotations, possibly multi-line. @DraftCode("Improve performance.") @CodeIssue("Set operations should be O(NlogN).") @CodeIssue("Search methods should be O(logN).") @CodeIssue(""" Editing methods should be O(logN). - Keep the tree balanced for worst-case performance of O(logN). - Sorted bulk insertions should be O(N) rather than O(NlogN). """) class MyClass { // ... }
Note that @*Issue
annotations make sense even in combination with @Complete*
development stage,
because they can describe planned future improvements or other ideas that are not technically flaws in the current implementation.
Cascading
In Java, program elements are arranged in a hierarchy with module at the top, methods at the bottom, and packages and classes inbetween. If Stagean annotation is applied to higher language construct, how does it affect nested language constructs?
@Complete*
and @No*
annotations imply that all nested elements have the same completeness (100% or 0% respectively).
They cascade to lower level elements. Explicit annotations on nested elements can still override this implicit cascading.
@Stub*
and @Draft*
annotations, on the other hand,
indicate average completeness of the annotated program element.
This average does not tell us anything about completeness of individual nested program elements.
For example, it is perfectly reasonable for a class annotated with @DraftDocs
to have some of its methods fully documented, some partially documented, and some undocumented.
In these cases, nested program elements have unknown completeness unless they are explicitly annotated.
@NoDocs @DraftCode("Add logging and metrics.") public class MyClass { @StubCode public void doSomething() { throw new UnsupportedOperationException(); } public void orOther() { // ... } // ... }
In the above example, all members inherit @NoDocs
annotation from MyClass
,
but @DraftCode
annotation does not cascade to class members.
Explicit @StubCode
annotation clarifies completeness of doSomething()
while orOther()
is left with unknown completeness.
Next steps
- Download Stagean from Maven Central if you haven't done so yet.
- Use javadoc for reference.
- Consider contributing.