一种基于代码语义和度量的代码异味识别方法
文献发布时间:2023-06-19 19:27:02
技术领域
本发明提供一种基于代码语义和度量的代码异味识别方法,属于软件工程代码异味识别领域。
背景技术
代码中存在异味表明该代码违反基本设计原则并对设计质量产生负面影响。代码异味的不断累积会带来技术债务,技术债务是一个隐喻,用于表示开发人员在开发过程中采取捷径实现快速交付的次优解决方案,它包括各种代码异味、反模式、硬编码、不必要的代码重复、不遵循已有的设计规约等。其中代码异味是技术债务的重要来源,代码异味的存在表明软件系统存在质量问题。软件系统中的大量代码异味会导致较差的可维护性,进而导致软件难以进化。因此,识别代码异味并定期对其进行重构是保持低技术债务的必要条件。
代码异味是代码片段中可能表示深层问题的任何特征。识别一个代码片段是否具有异味是主观的,并且因程序语言,开发人员和开发方法而异。因此,设计一个可以自动化识别代码异味的人工智能模型以适用于不同语言和代码粒度是非常有必要的。
现有的用于检测代码异味的工具依赖于预设的规则和固定的度量阈值。开发者将这些工具当作技术顾问来追踪代码异味。然而,判断一个代码片段是否具有异味没有统一的判断标准,换句话说,这是主观的,研究表明这些工具并不能准确的从代码度量中捕捉到需要重构的最重要部分。因此,一些发明人使用机器学习或深度学习的方法来自动检测代码异味,以期望模型学习人为识别代码异味的经验而不是靠固定的规则和阈值。但是他们考虑的代码信息比较单一,而且所采用的方法较为简单,以至于导致识别精确度不高。
如上所述,当前的代码异味检测工具依赖于预设规则和度量阈值,它们忽略了代码中隐含的语义以及度量之间的相互关系。一方面,预设规则通常通过匹配特定代码模式来识别异味。尽管有些方法使用神经网络来学习隐藏在抽象语法树中的代码上下文信息,但它们并不能充分学习代码语义并忽略代码度量。另一方面,基于度量的方法在识别可测量异味方面非常有效。然而,软件工程师很难手动调整经常相互矛盾和相互关联的阈值。
发明内容
针对现有技术存在的上述两方面问题,本发明提供一种基于代码语义和度量的代码异味识别方法,包括以下步骤:
S1构建代码异味数据集,所述代码异味数据集中的样本为通过自动化方法收集得到的因代码异味问题而在项目历史版本迭代过程中被真实重构前后的代码片段;
S2对所述代码异味数据集中的代码片段进行数据预处理,得到代码语义表征信息和代码度量信息;
S3构建代码语义表征学习模型,将所述代码语义表征信息输入代码语义表征学习模型,得到代码语义嵌入;
S4构建代码度量关系学习模型,将所述代码度量信息输入代码度量关系学习模型,得到代码度量关系嵌入;
S5将所述代码语义嵌入和代码度量关系嵌入进行融合,得到融合学习模型,所述融合学习模型用于检测代码异味;
S6构造所述融合学习模型的损失函数,对所述融合学习模型进行训练,得到代码异味识别模型;
S7将待检测的代码片段经过所述步骤S2中的数据预处理后,得到待检测代码片段的代码语义表征信息和代码度量信息,将所述待检测代码片段的代码语义表征信息和代码度量信息输入所述代码异味识别模型,得到代码异味识别结果。
作为优选,所述步骤S1中,所述代码片段来源于开源的大型代码仓库中;所述自动化方法包括:利用代码异味检测工具和预设规则来自动收集来自所述代码仓库中的因代码异味问题而在项目历史版本迭代过程中被真实重构前后的代码片段。
作为优选,所述步骤S2中,预处理得到代码语义表征信息的方法为:使用代码语法解析工具解析出代码的类级别和方法级别的抽象语法树,然后通过在所述抽象语法树中添加控制流和数据流边缘来构建得到代码图表征的流增强抽象语法树。所述流增强抽象语法树提供丰富的代码结构和语义;
预处理得到代码度量信息的方法为:利用代码异味检测工具来计算面向对象的代码度量;将所述代码语义表征信息和代码度量信息以字典的格式保存在JSON文件中以便于模型读取。
作为优选,所述步骤S3中,所述代码语义表征学习模型包括一个词元嵌入层、若干图神经网络层、一个卷积神经网络层;通过堆叠若干所述图神经网络层以学习所述流增强抽象语法树的语义信息,并在每个所述图神经网络层后接一个非线性激活函数;
所述步骤S3具体包括以下步骤:
首先将流增强抽象语法树送入词元嵌入层使得流增强抽象语法树中的所有文本信息均由词向量表示,得到向量化后的流增强抽象语法树,然后将向量化后的流增强抽象语法树输入所述语义表征学习模型,然后采用基于注意力机制的全局池化层读出每个图神经网络层的输出特征,然后将所述输出特征进行拼接后,输入一个由卷积神经网络层和非线性激活函数构成的输出层进行融合,得到代码语义嵌入。
作为优选,所述步骤S4中,所述代码度量关系学习模型包括一个度量嵌入层、一个位置嵌入层、若干Transformer层、一个卷积神经网络层;通过堆叠若干所述Transformer层用于学习代码度量之间的制约关系;
所述步骤S4具体包括以下步骤:首先将所述代码度量信息送入度量嵌入层对代码度量进行向量化编码,得到度量嵌入,然后将度量嵌入输入位置嵌入层用于编码度量排列次序,得到经过位置编码后的度量嵌入,将所述经过位置编码后的度量嵌入输入由若干Transformer层堆叠的网络,并将最后一层所述Transformer层输出的特征进行拼接后输入到一个由卷积神经网络层和非线性激活函数构成的输出层进行融合,得到代码度量关系嵌入。
作为优选,所述步骤S5具体包括以下步骤:将S3得到的代码语义嵌入和S4得到的代码度量关系嵌入采用拼接操作进行融合,然后将融合后得到的特征,输入由全连接网络构成的分类器,得到融合学习模型,用于识别代码异味。
作为优选,所述步骤S6中,所述损失函数为基于交叉熵损失函数优化构造出的融合学习模型中所述分类器的损失函数,所述损失函数用于对所述融合学习模型进行训练。
作为优选,所述面向对象的代码度量,包括:代码行数、圈复杂度、参数数量、代码行数、字段个数、公共字段数、方法数量、公共方法数量、每个类的加权方法、子类数量、继承树深度、方法中聚合的不足、扇入、扇出。
本发明通过向抽象语法树中添加控制流边和数据流边构造出语义丰富的流增强抽象语法树,并采用图神经网络来学习代码语义表征。另外,本发明还采用基于自注意力机制的Transformer层来学习度量之间的相互关系。最后,通过融合学习代码的两种模态的数据来共同识别代码异味。本发明具有以下有益效果:
1.本发明提供一种自动化收集代码异味数据集的方法,可以方便快速获取大量真实数据样本用于模型训练;
2.本发明首次同时考虑采用代码语义信息和代码度量信息来共同识别代码异味,适用于识别更多种类的代码异味;
3.本发明提供一个精心设计的融合学习模型,可以充分学习代码语义信息和代码度量之间的制约关系,使模型可以同时分析与代码异味相关的两种重要代码信息,对代码异味识别精确更高。
附图说明
为了更清楚地说明本发明具体实施方式或现有技术中的技术方案,下面将对具体实施方式或现有技术描述中所需要使用的附图作简单介绍,后文将参照附图以示例性而非限制性的方式详细描述本发明的一些具体实施例。附图中相同的附图标记标示了相同或类似的部件或部分。本领域技术人员应该理解,这些附图未必是按比例绘制的。附图中:
图1为本发明实施例所提供的基于代码语义和度量的代码异味识别方法流程图。
图2为本发明实施例所提供的数据集构造方法(正负样本自动采样策略)。
图3为本发明实施例所提供的基于自注意力机制的Transformer层学习代码度量之间相互关系的原理图。
具体实施方式
为了使本申请的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本申请进行进一步详细说明。应当理解,此处描述的具体实施例仅用以解释本申请,并不用于限定本申请。
为了更好的理解本发明的技术方案,下面结合附图对本发明实施例进行详细描述。应当明确,所描述的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其它实施例,都属于本发明保护的范围。
首先,对本申请实施例中涉及的名词进行简要介绍:
抽象语法树(Abstract Syntax Tree,AST):一种基于代码语法的树结构的代码表示,其非终端节点(内部节点)表示操作符(算术或赋值),终端节点(叶节点)表示操作数(常量或标识符)。
流增强抽象语法树(Flow-Augmented Abstract Syntax Tree,FA-AST):一种基于抽象语法树构造的图结构的代码表征,它是通过向原始抽象语法树中添加控制流和数据流等边来构造的。
图神经网络(Graph Neural Network,GNN):一种利用深度学习直接对图结构数据进行学习的框架,其优异的性能引起了学者高度的关注和深入的探索。通过在图中的节点和边上制定一定的策略,GNN将图结构数据转化为规范而标准的表示,并输入到多种不同的神经网络中进行训练,在节点分类、边信息传播和图聚类等任务上取得优良的效果。
Transformer:一种基于自注意力机制和前馈神经网络构造的神经网络模块,在自然语言处理和计算机视觉等领域取得了非常不错的表现。
卷积神经网络(Convolutional Neural Network,CNN):是深度学习中非常常见的算法(模型),其在图像处理中应用广泛。
词元嵌入(Token embedding):一个对文本自动编码的算法,通过输入所需词库中词的数量和所需词嵌入的维度,自动生成包含词库中所有词的词嵌入的词表。
度量嵌入(Metric embedding):类似于词元嵌入,通过输入所需度量值库中度量值的数量和所需度量嵌入的维度,自动生成包含度量值库中所有度量值的度量嵌入的度量值表。
位置嵌入(Position embedding):一个对输入的一串向量进行位置编码的算法,用于标记每个向量的次序,在本发明中用于标记输出一系列度量值的次序,为了编码不同位置的度量值的含义的不同。
本发明提供一种基于代码语义和度量的代码异味识别方法。首先,通过自动收集大量代码异味在项目历史版本迭代过程中被真实重构前后的样本,构造出代码异味数据集。然后,对构造出代码异味数据集的代码片段进行数据预处理,得到代码语义表征信息和代码度量信息。之后,将代码语义表征信息输入代码语义表征学习模型,得到代码语义嵌入;将代码度量信息输入代码度量关系学习模型,得到代码度量关系嵌入。接着将代码语义嵌入和代码度量关系嵌入进行融合,得到融合学习模型,用检测代码异味。最后,构造融合学习模型的损失函数,用于对融合学习模型进行训练,得到代码异味识别模型,用于识别含义代码异味的代码片段。
本发明所提供方案的过程为:1)自动收集大量代码异味在项目历史版本迭代过程中被真实重构前后的样本,构造出代码异味数据集;2)对所述构造出代码异味数据集的代码片段进行数据预处理,得到代码语义表征信息和代码度量信息;3)将所述代码语义表征信息输入代码语义表征学习模型,得到代码语义嵌入;4)将所述代码度量信息输入代码度量关系学习模型,得到代码度量关系嵌入;5)将所述代码语义嵌入和代码度量关系嵌入进行融合,得到融合学习模型,用检测代码异味;6)构造融合学习模型的损失函数,用于对融合学习模型进行训练,得到代码异味识别模型,用于识别含义代码异味的代码片段。7)将待检测的代码片段经过数据预处理后输入代码异味识别模型,得到代码异味识别结果。
本发明实施例给出一种基于代码语义和度量的代码异味识别方法,图1为本发明实施例所提供的代码异味识别方法的流程示意图。如图1所示,该方法包括以下步骤:
步骤101,自动收集大量代码异味在项目历史版本迭代过程中被真实重构前后的样本,构造出代码异味数据集。本发明基于两个假设收集数据集:1)代码异味检测工具具有一定的可信度,可以部分检测需要重构的代码异味;2)随着项目版本的迭代,一些异味可能会被引入,一些可能会被消除。根据以上假设,本发明从线上开源的大型代码仓库中利用代码检测工具和预设规则来自动收集大量代码异味在项目历史版本迭代过程中被真实重构前后的样本。具体地,如图2所示,本发明收集一个项目在所有版本下的代码片段构成一个代码片段集合C,并使用C
规则1(图2案例1):当S
规则2(图2案例2):当S
规则3(图2案例3&4):从创建的版本保存到最新版本的代码片段总是被工具检测为非异味(图2案例3)或异味(图2案例4),它的总版本占项目总版本的90%以上,将它们视为负样本,且将图2案例3和图2案例4的负样本数设置为相等。
步骤102,对所述构造出代码异味数据集的代码片段进行数据预处理,得到代码语义表征信息和代码度量信息。本发明使用代码语法解析工具提取项目代码的类级别和方法级别的抽象语法树,然后通过在原始抽象语法树中添加控制流和数据流边缘来构建流增强抽象语法树,以提供丰富的代码结构和语义。针对代码度量的关系信息,本发明利用代码异味检测工具来计算13种常见的面向对象的代码度量,具体如表1所示。此外,本发明将两种代码信息以字典的格式保存在JSON文件中以便于模型读取。
表1.面向对象的代码度量明细
步骤103,将代码语义表征信息输入代码语义表征学习模型,得到代码语义嵌入。代码语义表征学习模型主要包括一个词元嵌入层、若干图神经网络层、一个卷积神经网络层。本发明主要通过堆叠若干图神经网络层来学习代码图表征流增强抽象语法树的语义信息,且每个图神经网络层后接一个激活函数。具体地,本发明首先将流增强抽象语法树送入词元嵌入层使得流增强抽象语法树中的所有文本信息均由词向量表示,然后将向量化后的流增强抽象语法树数据输入由若干图神经网络层构成的网络,然后采用基于注意力机制的全局池化层读出每个图神经网络层的输入特征,然后将这些读出的特征拼接,最后,将它们输入到由卷积神经网络层和非线性激活函数构成的输出层,得到代码语义嵌入。其中本发明所采用的图神经网络层的节点信息更新公式为
其中
其中eLU是一个激活函数,f
步骤104,将代码度量信息输入代码度量关系学习模型,得到代码度量关系嵌入。代码度量关系学习模型主要包括一个度量嵌入层、一个位置嵌入层、若干Transformer层、一个卷积神经网络层。本发明主要通过堆叠若干Transformer层用于学习代码度量之间的制约关系。Transformer模型由编码器和解码器两部分组成,其中编码器部分由若干个编码器层堆叠而成,每个编码器层由一个自注意力层和一个前馈层组成。本发明采用Transformer的编码器部分来作为代码度量关系学习模型的特征提取网络,用于提取代码度量关系信息。其原理如图3所示,一方面,Transformer层自动计算每个指标与其他指标之间的相关性,省去了手动选择相关性最高的指标的工作;另一方面,它从每个度量的角度输出全局度量信息,其中包含所有度量之间的相互约束。在代码度量关系学习模型中,本发明将代码度量序列作为输入,并从一个随机初始化的度量矩阵获得度量嵌入。其次,位置嵌入将位置信息分配给度量序列中的每个度量,这使得具有相同值的不同度量具有不同的含义。然后,将这些位置编码的数据输入到由几个Transformer层和与输入大小相同的输出特征组成的编码器中。最后,将这些特征向量连接起来,并将它们输入到由卷积神经网络层和非线性激活函数构成的输出层,得到代码度量关系嵌入。其中输出层的计算公式与步骤103中计算输出层的公式相同。步骤105,将代码语义嵌入和代码度量关系嵌入进行融合,得到融合学习模型,用于识别代码异味。本发明将步骤103得到的代码语义嵌入和步骤104得到的代码度量关系嵌入进行拼接融合,然后将拼接融合后的特征输入由全连接网络构成的分类器,得到融合学习模型,用于识别代码异味。
步骤106,构造融合学习模型的损失函数,用于训练代码语义表征和度量关系学习的融合学习模型,得到代码异味识别模型。本发明为了优化样本不平衡问题,基于交叉墒损失函数优化构造出融合学习模型的二分类器的损失函数:
其中N表示批大小,α平衡正负样品,γ调节易识别和难识别样品,BCE表示二进制交叉熵损失函数,本发明将α设为1,γ设为2。
步骤107,将待检测的代码片段经过步骤102中数据预处理后输入所述代码异味识别模型,得到代码异味识别结果。
经过以上步骤,将预处理好的两种代码数据输入本发明提供的模型中进行训练,经过若干轮次,训练好的模型可用于识别真实世界项目中的代码异味。
以上所述,仅为本发明部分具体实施方式,但本发明的保护范围并不局限于此,任何熟悉本领域的人员在本发明揭露的技术范围内,可轻易想到的变化或替换,都应涵盖在本发明的保护范围之内。
- 一种基于图论的代码复用识别方法及系统
- 一种基于代码分割的个人代码质量度量方法和系统
- 一种面向软件代码单元和代码度量的代码变更序列方法