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:

Maven tool
<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:

All of the above solutions still apply. Stagean just adds another tool to your toolbox:

Development stages

Stagean recognizes four development stages:

@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:

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