字节工程师自研基于 IntelliJ 的终极文档套件

前言

众所周知,程序员最讨厌的四件事:写注释、写文档、别人不写注释、别人不写文档。因此,想办法降低文档的编写和维护成本是很有必要的。当前写技术文档的模式如图:

24f522ab8da6a43c8533b93b062a2b34.png

痛点总结有如下三方面:

05b252202e532f579a1c297e1fc9d05a.png

针对上述问题,我们的解决思路:

  • 本地的编辑、浏览工作收敛至 IDE,提供沉浸式体验;

  • 在文档、代码间建立强关联,减少拷贝,提升联动性,同时提升文档的触达率

  • 代码与文档同属一个 Git 仓库,借助版本管理,避免因业务迭代导致的文档版本与代码不匹配

  • 制作可将文档导出到线上的工具,可利用浏览器做到随时访问

方案总览

5e8242889be23468883a42f3799e665b.png

与原始模式相比,新方案可以做到完全脱离浏览器 / 文档编辑器,线上页面的同步完全交给定时触发的自动化部署。

图中橙色部分是方案的重点,按照分工,划分为线下、线上两部分,职责如下:

  • 线下:IDEA Plugin

    • 实现自定义语言的解析、分析;

    • 提供文档内容的预览器、编辑器;

    • 提供一系列实用功能,关联代码与文档;

  • 线上:Gradle / Dokka Plugin

    • 桥接、复用 IDE Plugin 的语义分析、预览内容生成能力;

    • 扩展 Dokka Renderer,实现 HTML 与飞书文档的导出能力;

方案建设使用了不少有意思的技术,放到后面详细介绍。

线下效果

IDEA Plugin 提供一个侧边栏和强大的编辑器。下面分别从编辑、浏览两个角度介绍。

编辑体验

假设存在源码如下:

public class ClassA {
    public static final String TAG = "tag";

    ClassB b;

    /**
     * method document here.
     *
     * @param params input string
     */
    public static void invoke(@NotNull String params) {
        System.out.println("invoke method!");
        System.out.println("this is method body: " + params);
    }

    public ClassA() {
        System.out.println("create new instance!");
    }

    private static final class ChildClass {

        /**
         * This is a method from inner class.
         */
        void innerInvoke() {
            System.out.println("invoke method from child!");
        }
    }
}

文档中添加该类的引用就是这个效果:

1abcf79d2d404930efafcfdb647af43f.gif

不同于复制、粘贴代码,新方案有如下优势:

  • 关联性更强,预览会随代码片段的变更时时改变;

  • 易于重构,被引用的类名、方法名、字段名发生重命名时,文档内容会自动随之变化,防止引用失效;

  • 更加直观,编辑、浏览时能更快速地找到代码出处;

  • 输入更流畅,有完善的补全能力;

浏览体验

a0ac6c40244661db08452a219a17514d.gif

相对于普通 Markdown,新方案用起来更加友善:

  • 沉浸式使用,界面内嵌在 IDE 内,无需跳转到其他应用;

  • 被提及的源码旁均有行标,点击一键查阅文档;

  • 文档“浏览器”支持与 IDE 一致的代码高亮、引用跳转;

线上效果

代码中文档会定期自动部署到远端。以一篇真实业务文档举例,HTML 部署到轻服务后长这样:

c754e3e048f65880c57172d306a6835b.png

对应飞书的产物长这样:

44378f485b1b85d036bb28a82bdeec4d.png

这些线上页面主要面向非当前团队的读者,内容由 CI 定时同步,暂不提供跳转到 IDE 的能力。

技术实现

项目的架构如图所示:

77f60d78e8b4ec6602d1c4d2cfe2d0b4.png

考虑到用户体验部分主要在 IDEA(Android Studio)内呈现,我们的技术栈选择基于 IntelliJ 打造。按模块可分为三部分:

  • 基建层

  • IDEA Plugin

  • Gradle / Dokka Plugin

通用逻辑(语言实现相关)封装在基建层,仅依赖 IntelliJ Core。相对于 IntelliJ Platform,IntelliJ Core 仅保留语言相关的能力,精简了 codeInsight、UI 组件等代码,被广泛用于 IntelliJ 各大产品中(包括图中的 Kotlin、Dokka 等)。

下面将针对这三个主要模块展开介绍。

基建

纵观整个方案,基建层是所有功能的基石,其最核心的能力是建立代码与文档关联。这里我们设计实现了一套标记语言 CodeRef,满足以下几个需求:

  • 语法简洁,结构上与源码一一对应;

  • 指向精准,即必须满足一对一的关系;

  • 支持仅保留声明(去掉 body),提升信噪比;

  • 有扩展性,方便后续迭代新功能;

CodeRef 语言并不复杂,采用类似 Kotlin/Java 的风格,用关键字、字符串、括号构成语句和代码块,代码块中每个节点都有与之对应的源码节点。下图是一个简单的示例,对应关系用着色文字标识:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值