随着软件开发和开源社区愈发普及,程序员这一群体正在飞速壮大,即便不是专业从事编程的人,会写或能看懂代码,几乎已经不是什么稀罕事。
然而再有经验的程序员,面对数十种风格迥异且分工不同的主流编程语言,难免会偶尔混淆不常用的语义和方法(Method),更别说这些语言的版本还会不断进化(Python 2.X到Python 3.X),甚至冒出一种全新语言,专门针对特殊领域,比如专门用于机器学习的Julia。
针对这一问题,Facebook的工程师采用了机器学习技术,开发出了一款名为Aroma的代码搜索和推荐工具。它可以拆解一段代码,分析其语义,然后在大型代码库中即时匹配出类似段落,按照相似程度推荐其他类似的代码写法,促进代码标准化和规范化。
研究人员认为,相比传统的代码搜索工具,Aroma具有以下几个优势:
不局限于代码中变量和参数的命名方式,因为Aroma并不是以字符串为单位搜索,只要大致语义相同,比如对象调用的方法相同,就会被捕捉到,而且多余的无关代码还会被省略,增加可读性。
Aroma会集合多组类似的搜索结果,用来生成一套代码建议,比单独呈现搜索结果更易理解。
面对超大规模的代码库,Aroma也能够做到及时反馈搜索结果,无需提前搜索代码规律。
Aroma的核心算法与编程语言无关,Facebook在Hack,JavaScript,Python和Java内部代码库中都部署了Aroma。
举个例子
为了更好地理解Aroma的原理,我们可以参考Facebook AI给出的例子。
假设我们想要在安卓系统中解码位图(bitmap),最基础的代码实现是这样的:
但是在实际应用中,只有这一行代码远远不够,最起码还要有用来处理异常的IOException,优化传递到decodeStream方法中的可选参数等等。
对于不熟悉安卓开发的新手来说,他需要去代码库或者开发者社区中搜索类似功能的实现方法,学一学大神的写法。这就轮到Aroma上场了。
按照Facebook软件工程师的描述,Aroma可以及时搜索与上述代码类似的代码段落。找到的一些代码是这样的:
仔细一看,三个搜索结果中的变量和参数的名字都不一样,但整体的确是符合代码语义的,具有一定的借鉴意义。
在此基础上,Aroma还会自动优化和整合这些结果,去掉对方法主体没有帮助的部分,使其更加泛化,最终成为一条有价值的代码写法推荐,像下面这段一样:
可以看出,推荐结果保留了上面三段代码中的相似部分,比如变量初始化和方法调用,但省略了异常处理和While循环等不同之处。
值得一提的是,Aroma会提供多组不同的代码推荐,因此其中仍然包括了异常处理的写法。
Aroma的实现方法
具体来说,Aroma的工作流程可以分为三大流程:特征提取和搜索,重新排名和聚类,组合并创建代码推荐。
首先,Aroma会为代码语料库中的每一个方法创建索引和解析树,从中提取出很多结构性的特性。这些特征都经过特殊挑选,而非一股脑地获取所有特征,反映出的信息包括变量用法,方法调用和控制结构等等。
最后它会基于特征,为每个方法创建一个稀疏向量,将所有向量组合起来,就成为了一个索引矩阵,可以用来搜索代码。
如果程序员编写了一段新的代码,Aroma就会用以上方法创建一个稀疏向量,然后对它和索引矩阵执行点积运算。这样一来,点积结果最高方法就是与新代码重合度最高的片段。Aroma的算法会选取排名前1000的方法,作为候选建议集合,进入下一流程。
在Aroma拿到相似的方法候选集之后,会将它们重新排名,然后聚类。由于之前的向量只能表示出特征存在与否的抽象信息,会包含一些与所搜代码本身不相关的段落,进而低估了代码片段与搜索结果的相似程度。
因此,机器学习算法会在方法解析树上修剪,去掉结果中与被搜索代码的不相关部分,仅保留最匹配的,并且将所有方法(搜索结果)重新排名。在这之后,Aroma会根据新的排名运行迭代聚类算法,找到多组相似的代码段落,将它们组合成一个个代码推荐集群。
有了集群之后,Aroma就可以执行最后一步——创建代码推荐了。简单来说,这一过程由一套交叉算法完成。它在一个代码片段的基础上,将同一集群中的多个代码片段迭代修剪,找到它们之间的共同点,整合成最终的代码推荐。
因为搜索结果可以分成若干个集群,最终的代码推荐也会有若干种不同风格,对应不同的实现过程,从而为程序员提供多样化的代码选择。
可以看出,Aroma的目的并非取代程序员,而是帮助他们从现有代码库中快速找到和学习优秀代码,加快编程速度和软件迭代速度,让机器学习,这个程序员创造出的产物,回过头来帮助自身进步。
在未来,编程或许将变成一个人机共同完成的任务,由人类提出高层次的,抽象的想法,具体的实现和代码编写则交给AI系统完成,实现效率的最大化。