如何记录带有变体的代码? (用于 ifs 的 JavaDoc)

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

tl;drifs 的 JavaDoc 吗?

简介

我正在为多个客户编写一个企业应用程序。 99% 的代码库是共享的,但时不时会有这样的变体:

if (user.hasModule(REPORTS)) { 
  ...conditional code... 
}

我现在想为用户记录所有这些变体。从文档中应该清楚如果我打开例如会发生什么。模块 REPORTS。我认为该文档应该以 JavaDoc 方式编写——这意味着它应该尽可能接近条件代码。它可能看起来像这样:

/** Enables the cool report. */
if (user.hasModule(REPORTS)) { 
  ...conditional code... 
}

或者这样:

@Doc(text="Enables the cool report.")
if (user.hasModule(REPORTS)) { 
  ...conditional code... 
}

或者这样:

if (user.hasModule(REPORTS, "Enables the cool report.")) { 
  ...conditional code... 
}

结果基本上是每个模块的注释列表。

Module    | Comments
----------+--------------------
REPORTS   | Enables the cool report.
REPORTS   | Allows exporting the reports.
IMPORT    | Allows importing the data.

问题

如何从代码中收集所有文档注释?我正在考虑几种方法:

源码提取

这需要解析器遍历源代码,找到所有此类条件并获取对(模块、注释)。但是,它必须连接到编译器以避免出现奇怪的格式问题(长行中间的换行符等)。

动态提取

每当在运行时调用 user.hasModule() 时,它都会记录其实际参数,然后使用此日志来构建文档。因此,例如在 Beta 测试期间收集文档,然后将其构建到最终版本中。缺点很明显:如果系统的某个部分未被访问,则不会被记录。

字节码提取

为了避免乱七八糟的源代码,人们可以直接找到编译后的字节码,用类似ASM的东西分析它,找到所有调用user.hasModule()的地方。这是我最喜欢的版本,但卡住了 以及如何计算调用时 VM 堆栈顶部的实际值是什么 invoke_static。必须有一个更简单的方法:)

总结

有这方面的工具吗?我是否缺少一种简单的方法来做到这一点?我在尝试记录此类情况时是否完全被误导了?谢谢!

我认为您的代码中缺少一个概念。

你的模块看起来很像安全 groups,每个用法看起来很像 permission

如果您以这种方式建模,您可以将每个模块的 usages/permission 知识集中到一个位置。这样就不需要通过静态分析来扫描代码了。

下面的方案使用 Java 类型系统来确保您不能在没有先为该模块创建新权限的情况下为该模块添加 if 语句。

只需java 遍历枚举值,就可以从这段代码轻松生成完整的权限和描述列表。

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
  }

这很可能是矫枉过正 - 一个没有所有自输入废话的简单枚举可能就足够了。

if user.hasPermission(Permissions.Export)

我会将 user.hasModule(REPORTS)==true 时执行的代码放入 aspect 中。然后用 JavaDoc 记录方面。