How to document code with variants? (JavaDoc for ifs)
tl;dr is there JavaDoc for if
s?
Intro
I am writing an enterprise application for multiple customers. 99% of the code base is shared, but every now and then there is a variant like this:
if (user.hasModule(REPORTS)) {
...conditional code...
}
I would now like to document all these variants for the users. It should be clear from the documentation what happens if I turn on eg. the module REPORTS
. I believe this documentation should be written in the JavaDoc manner - meaning it should be as close as possible to the conditional code. It could look like this:
/** Enables the cool report. */
if (user.hasModule(REPORTS)) {
...conditional code...
}
Or this:
@Doc(text="Enables the cool report.")
if (user.hasModule(REPORTS)) {
...conditional code...
}
Or perhaps this:
if (user.hasModule(REPORTS, "Enables the cool report.")) {
...conditional code...
}
The result would be basically a list of comments for each module.
Module | Comments
----------+--------------------
REPORTS | Enables the cool report.
REPORTS | Allows exporting the reports.
IMPORT | Allows importing the data.
Question
How to gather all the documentation comments from the code? I am considering several approaches:
Source code extraction
This would require a parser to traverse the source code, find all such conditions and fetch pairs (module, comment). It would, however, have to be hooked into the compiler to avoid problems with weird formatting (newlines in the middle of a long line etc).
Dynamic extraction
Whenever user.hasModule()
is invoked during the runtime it logs its actual arguments, this log is then used to build the documentation. So for example during the beta-testing the documentation is gathered and then built into the final release. The downside is clear: if a certain part of the system is not accessed, it will not be documented.
Bytecode extraction
To avoid the messy source code one can just reach for the compiled bytecode, analyze it with something like ASM and find all the places where user.hasModule()
is invoked. This is the version I like the most, but got stuck with how to figure out what is the actual value on the top of the VM stack at the moment of calling invoke_static
. There has to be a simpler way :)
Summary
Is there a tool for this? Am I missing a simple way to do this? Am I completely misguided in my attempts to document such conditions? Thanks!
I think you are missing a concept in your code.
Your modules look a lot like security groups , each usage looks a lot like a permission .
If you were to model things this way you could concentrate the knowledge of what the usages/permission were for each module into one location. There would then be no need to scan through the code via static analysis.
The scheme below uses the Java type system to ensure you could not add an if statement for a module without first creating a new permission for that module.
A complete list of permissions and descriptions could be easily generated from this code with a little java looping through the enum values.
public interface User {
public <T extends Module<T>> boolean hasPermission(Module<T> module, Permission<T> usage);
}
public interface Permission<T extends Module<T>> {
String describe();
}
enum Reports implements Module<Reports> {
REPORTS
}
enum ReportsPermissions implements Permission<Reports> {
ENABLE_COOL_REPORT("Enables the cools reports"),
ALLOWS_EXPORTING_THE_REPORTS("Allow exports the cools reports");
private final String description;
ReportsPermissions(String description) {
this.description = description;
}
@Override
public String describe() {
return description;
}
}
enum ImportPermissions implements Permission<Import> {
ALLOWS_IMPORTING("Allows importing the data.");
etc
}
This is most likely overkill - one simple enum without all the self typing nonsense is probably enough.
if user.hasPermission(Permissions.Export)
I'd put the code that's executed when user.hasModule(REPORTS)==true
into an aspect. Then document the aspect with JavaDoc.
上一篇: 从C中定义Python类