Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to document code with variants? (JavaDoc for ifs)

Tags:

java

javadoc

tl;dr is there JavaDoc for ifs?

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!

like image 896
vektor Avatar asked Feb 03 '15 16:02

vektor


2 Answers

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)

like image 73
henry Avatar answered Sep 21 '22 05:09

henry


I'd put the code that's executed when user.hasModule(REPORTS)==true into an aspect. Then document the aspect with JavaDoc.

like image 21
Andres Avatar answered Sep 22 '22 05:09

Andres