智能化软件开发沙龙微访谈系列第6期:“代码克隆分析与管理”讨论汇编
01
背景介绍
01
代码克隆,即相同或相似的重复代码片段,普遍存在于开源及企业软件系统中。代码克隆不仅意味着
重新发明轮子所带来的额外工作量和开销
而且给软件维护和演化带来了多个方面的问题,包括一致性维护、代码复杂性、破坏设计结构等。
此外,大范围的开源代码复用以及软件生态系统还造成了大量跨项目的代码克隆,从而进一步引发代码许可证、隐含缺陷、安全漏洞等方面的问题。
因此,在全面消除代码克隆并不现实的情况下如何对其进行有效的检测和管理,全面掌握内部(企业内部软件生态系统)及外部(开源社区及其他外部软件生态系统)代码克隆状况,并对相关的代码与设计质量、一致性维护、缺陷与安全漏洞等问题进行有效管理,就成为软件企业面临的现实问题。本次微访谈围绕代码克隆分析与管理这一主题,邀请了来自学术界及工业界的多位知名技术专家进行访谈,共同探讨对于代码克隆问题的感受和理解、相关技术诉求和痛点以及所开展的实践探索,促进相关领域学术研究的发展以及产学研合作。
02
微访谈嘉宾
02
嘉宾
刘扬
新加坡南洋理工大学,AssociateProfessorandUniversityLeadershipForumChair
*泥
华为研发能力规划负责人、软件工程方法和工具专家
*映农
微软AzurePrincipalDataScientistManager
张刚
软件开发方法学专家、Bell实验室杰出工程师
刘力华(息羽)
阿里巴巴代码平台代码智能化负责人
包晓晶
中汇信息技术总工办负责人
主持人
彭鑫(兼主持人)
复旦大学教授
03
访谈记录
03
QUESTIONI
请简要总结下您所了解的各种典型的代码克隆类型,例如根据粒度(代码片段、文件、模块、项目等)、形态(源代码、二进制代码等)、成因(内部复用、外部代码拷贝、分支合并、偶然相似等)、相似度程度(完全相同、编辑性修改、功能相似等)等方面进行分类。
*泥
我们发现的代码克隆或相似代码拷贝的形态和成因。包括源代码片段,源文件,二进制lib库,项目等。大小从几十到几万行不等。成因包括从其他项目拷贝,从开源拷贝,从搜索引擎和问答系统拷贝,从教课书和参考书拷贝,合并分支或者版本,独立个人或项目自然写出的相似代码,代码库闭源/分散/多套,产品的多形号,多形态。产品间,产品和平台间的拷贝复用造成等。在公司规模大,产品多和生命周期长的情况下,代码克隆的情况是非常多的
彭鑫
看来代码克隆的粒度大到项目、模块,小到代码片段都有,产生的原因也是多种多样。
*泥
服务的实现代码也是有可能相互拷贝的。
息羽
现有的很多Type3级的工具都支持了代码片段、文件、模块、项目的扫描,有的是基于源码token或者语法树的比对,也有的基于比如Java基于字节码的对比,应用的方向可能内部复用、外部代码拷贝、分支合并会比较多一点,现在最多的还是Type3的相似,Type4的研究虽然很多,但是真正在工业界落地的还是很少的。
彭鑫
Type4确实很难。这里解释一下,Type3是指略有编辑差异(例如插入新的代码行或删除代码行)的重复代码,而Type4则是看上去基本不像,但功能相似的代码(语义克隆)。
*映农
前面*总谈到很多克隆来源。息羽谈到Type3,type4。我从另外一个角度谈一下。我这里试图从人的角度对克隆代码进行一下分类,也就是从克隆代码的复用者和源代码的提供者之间的关系来做个分类。
第一,自我复用,程序员复用自己的代码,通常是较低层的businesslogic。用于快速原型试验阶段,或者测试代码。潜在问题包括bug的传播,由原型开发过渡到产品开发未及时清理克隆代码,造成产品大的memoryfootprint,bug传播,等等。
undefined
第二,开发小组内复用,一个项目内部小组成员之间互相leverage,大多发生在项目进度压力大,没有时间立即重构。应该根据项目进展情况安排重构代码。潜在问题是重构计划迟迟排不上日程,导致增加产品bug修复的复杂度(每一份克隆拷贝都需要修复),产品优化的复杂度(每一份克隆都需要做类似的优化)。
undefined
第三,企业内部复用,不同项目组直接复用一个商业逻辑库或者微服务的代码。复用的目的是减少项目之间的耦合性。潜在问题是bug的广泛传播,一方修复bug,另一方很难得到及时通知,造成产品质量问题。和安全漏洞相关的bug是尤其严重的一直类型。
undefined
第四,开源复用,目前各个公司利用开源代码已经相当普遍,优点是大大增强生产力。潜在问题也很多,主要包括customization的代价,开源代码质量参差不齐,搞不好水土不服现象严重,反而会降低生产力。
讨论环节:
陈鹏飞:*泥如果软件全部变成细粒度的服务化,比如现在比较热的纳米服务,FaaS,是不是就不用在做代码克隆了*泥:服务的实现代码也是有可能相互拷贝的。息羽:阿里也在推FaaS,但是服务化个人觉得不会消灭拷贝,但是对于减少拷贝还是有效果的,工程师的拷贝是无法避免的。刘扬:type4在检测方面里面是最难的,之前学术界做的不多。在安全分析里面很重要,一个安全漏洞的源程序可能编译成intel和arm的binary,到了binary以后由于编译器和指令集不一样,只能用type4来找克隆。最近两年有一些PL的文章和安全的文章来解决binary里面type4的检测,但是要平衡好准确率和效率还是不容易的。QUESTIONII
代码克隆对于企业软件开发的各个方面造成了哪些问题和影响?根据您的了解,大家对于这些代码克隆存在的合理性及其危害性有什么样的认识和感受?
*泥
代码克隆带来了知识产权和合规风险;代码规模不合理的增大,低水平重复性工作,维护成本的增大;整体休bug,补丁,升级速度变慢。在局部对重用,对开发速度有帮助。
息羽
有句戏言程序员的工作就是“复制粘贴”,大部分工程师都避免不了,如果是对于工程内部的克隆,很容易导致工程存在大量冗余代码,代码复用率较低,到后期可维护性很差,如果需要改一个bug或者新增一个需求,需要在多个类似的地方修改,降低了工程师的开发效率,同时也存在较大的质量隐患。如果是对于工程外部的克隆,比如克隆开源社区的代码,还容易引起开源协议的问题。
*映农
代码克隆是软件开发过程中知识和劳动成果复用的重要方式之一。优点是快速,缺点很多,比如bug扩散,维护困难,等等。但是,快速复用的优点是如此的吸引广大开发者,所以,克隆代码是相当普遍的现象。如果对于克隆代码的行为和产生的代码管理不好,危害也是相当的大。直接危害包括产品的性能和质量,和开发团队的生产力。质量问题的一个特别的例子是克隆代码导致产品的零日漏洞。
包晓晶
代码克隆在短期内对项目开发的进度还是有些好处的,但带来的一个最直接的问题就是长期的可维护性。功能和命名都差不多但又略有差别的代码对熟练工可能不是一个问题,但是对于新加入项目组的同事来说就是灾难了,理解起来非常困难,出了问题排查耗时增加,修复和测试验证的成本都会大幅上升,后续的知识传承也会是个问题。协议合规性方面的问题我们暂时还没遇到,不过如前面各位所言,确实也是一个潜在的风险。
刘扬
由于代码量的增加和开源软件的流行,代码克隆的检测和管理已经变成了一个(中大型)企业的严重问题。我了解的比较集中的问题是在不同项目里面的相同开源项目的版本检测和维护。这里面2个比较严重的危害是:
01
开源项目已知漏洞的检测和维护。尤其是最近两个著名的安全事件PanamaPapers和Equifax(4亿美元的损失),黑客基于旧的开源软件的已知漏洞攻击。由于已知漏洞的攻击非常容易。所以这个问题目前在安全行业界也比较重视。
02
开源项目兼容性的检测和维护。在大公司里面BAT,很多时候同一个开源项目的很多版本都在用,维护起来很难,如何自动检测不同版本的兼容性是很重要的问题。
对于细粒度的克隆检测维护,这个也有需求。还有一个就是细粒度的克隆的同步更新问题和合并。另外一个是漏洞克隆代码的检测方面。不管是源码(类型三)和二进制代码(类型四)都有很强的需要。
张刚
危害大家说了很多了,我说说没有克隆的好处吧:)
我的一个心得是,即使不懂得任何设计模式,通过持续移除重复,很多模式都会自然浮现到代码中。我认为重复代码大多数时候都是影响维护性和扩展性的,因为重复是最强的耦合嘛。
我认识的大多数比较资深的程序员,包括我本人,都相信“代码的重复是一种坏味道”。我是真的会对自己的代码做克隆检测的(当然我也会做一大堆各种风格的检查和漏洞检查,尽量消除问题),也会比较刻意的去做一些重构。这是一种非常好的习惯。
我其实是不太相信代码克隆能带来啥好处的,除了没办法~~~
讨论环节:
彭鑫:刘杨”2)开源项目兼容性的检测和维护。在大公司里面BAT,很多时候同一个开源项目的很多版本都在用,维护起来很难,如何自动检测不同版本的兼容性是很重要的问题。”这一点与代码克隆的关系有点没理解。传统的兼容性问题是同一段代码在不同硬件和软件平台上的运行问题。吴毅坚:这个是说针对平台做过的修改吧。这样会出现一些type3克隆?刘旭:我感觉是不是因为同时load了几个版本,会导致运行时用的版本与开发不同,从而引发bug?刘扬:公司里维护很多版本的代价是很高的,安全漏洞是其中主要一个原因,版本越多,有一个比较久的漏洞,所以版本都得补。为了减少版本,就得考虑兼容性,但是兼容性更复杂,没人想没事就升级一下。吴毅坚:我感觉很多企业的程序员本身是倾向于克隆代码的,因为这样会比较快,在没有管理约束的情况下,大家会选择“欠债”的方法来提升自己代码的开发“效率”。不知道企业专家们是不是这样看的?包晓晶:吴毅坚确实是如此,所以需要通过流程、组织结构的设置来规避这种捷径。张刚:吴毅坚我觉得自律的程序员不会欠债,刻意欠债的程序员是没有追求的,不得不欠的债的是一个问题。吴毅坚:相比于自律的开发者,我觉得更多的还是不太自律的开发者,因此从技术和管理上都需要提供对代码克隆的更快和更actionable的反馈,让不动脑子的开发者也能做出好的程序,这样才能提升工程化水平呢。包晟临:吴毅坚你提到“自律的开发者”,那开发者是不是应该有些基本的自律,自律是否能规范成一些行为准则?吴毅坚:广义上,codeofethics应该包括这些吧。但是就像道德,当有人不遵守的时候,还是得有法律来管。然后法律还需要一些技术手段来支撑。QUESTIONIII
"总的来说,代码克隆还是给软件开发带来了很多问题以及额外的负担,那么为什么代码克隆在企业和开源软件中如此普遍呢?有哪些技术、管理或其他方面的原因造成许多优秀的程序员也在不断制造代码克隆呢?"
息羽
通常有下面几种情况:
1、在开发过程中,不知道所需要写的代码已经被其他人实现过了,存在认知的局限性,需要通过代码推荐/搜索一类的工具去帮助工程师。
2、工程师需要写一个代码,但是发现同样功能的代码已经实现过了,但是又因为各种原因(工程架构问题、外部工程等)无法直接引用,只能克隆一份。
这个更多的是一个工程架构的原因,如果前期工程设计比较好,有的地方需要做成二/三方包,有的地方需要放到工具类等等,都会减少引用问题带来的代码克隆。
3、由于需求/故障的紧急性,工程师没有时间去考虑代码克隆带来的问题,通过克隆并微调的方式优先快速的解决需求/故障,但是事后又忘记去做重构。
这个一方面需要一个好的架构,另一方面需要从管理上形成相应的应对机制,比如处理完故障之后需要通过复盘去回顾总结,并重构修改的代码。除此之外,CodeReview是解决代码克隆的非常有效的工具。
4、有很多优秀的工程师,更喜欢炫技,终觉得别人写代码不好,想重新造轮,到头来实现的代码也是差不多的。
*映农
很赞同息羽的回答。我就不再赘述。问题是(1)如何用有效的工具来最小化克隆代码带来的负面影响,(2)如何提高程序员对克隆代码潜在危害的awareness,从而在主观上积极的减小负面影响。
*泥
陈鹏飞:*泥如果软件全部变成细粒度的服务化,比如现在比较热的纳米服务,FaaS,是不是就不用在做代码克隆了*泥:服务的实现代码也是有可能相互拷贝的。息羽:阿里也在推FaaS,但是服务化个人觉得不会消灭拷贝,但是对于减少拷贝还是有效果的,工程师的拷贝是无法避免的刘扬:type4在检测方面里面是最难的,之前学术界做的不多。在安全分析里面很重要,一个安全漏洞的源程序可能编译成intel和arm的binary,到了binary以后由于编译器和指令集不一样,只能用type4来找克隆。最近两年有一些PL的文章和安全的文章来解决binary里面type4的检测,但是要平衡好准确率和效率还是不容易的。代码配置管理不完善,产品的形态多,组织间代码库封闭,多个代码库也会照成克隆。
包晓晶
从项目过程来看,迫于时间和成本的压力、对应开发人员的技术能力和对原有代码的熟悉程度、规避修改原有代码可能带来的潜在风险都会让开发人员选择代码克隆。
从管理上,代码分析检测的工具需要和我们研发使用的流程、工具链相结合才能发挥效果,单独给开发提供一个工具最终会由于各种原因最终被开发人员所忽略。
刘扬
这个我是真不懂,我的理解是TTM的压力,避免重复造轮子和多人大团队同时开发(多个branches)导致了克隆代码必然存在。我感觉克隆代码产生的原因主要是缺乏管理和工具的使用?大部分公司不会明确的提出代码克隆是个问题,但事实上是个很大的问题,等问题有了的时候,就比较痛苦了。
张刚
说到普遍性这个问题,我还是希望区分“工具检测到的克隆”和“程序员刻意的克隆”。前面已经提了一些工具检测到的克隆其实是误报的问题。这个是提升检测能力应该做的事情。
程序员刻意的克隆,这个很糟糕。优秀的程序员除非语言特性不支持,都不会刻意制造克隆,当然有些不可客服的管理原因除外。缺少时间往往并不是一个理由。
讨论环节:
*泥:代码提交和codereview时要及时检测出来和反馈。*映农:代码提交和codereview时要及时检测出来和反馈,太正确了。QUESTIONIV
应对代码克隆的前提条件是进行准确的检测和分析。在代码克隆检测和分析方面,您所在的企业或者研究组以及所了解的其他企业进行了哪些实践和探索,取得了哪些进展和成果,还存在哪些痛点以及需要进一步解决的问题?
*泥
我来总结一下。代码克隆或相似代码查找匹配的几个应用场景和实践:
a知识产权,license判断。判断一段代码是否存在抄袭,是否借用其他人代码,是否同公司内已有代码,或者同某个开源项目代码相似。
b修改升级的传播扩散。根据已有的bug修改或者升级修改代码片段,在代码库中查找到类似的代码,同步修改或者优化。
c代码重构辅助。对相似的代码片段聚类,辅助重构成函数或者模块。
d根据文本的自然语言语意,查找代码库中完成相应功能的代码片段。
e检查代码库中开源代码和商用库的不同版本的依赖和使用情况。
息羽
我们目前为了更好的扩展性和兼容性,实现了Type3级的代码克隆,相对于常用的SoucererCC、Nicad等工具,效果要好一些,针对阿里庞大的代码量,我们开发了大规模并行相似代码挖掘,通过聚类的方式快速的从整个集团代码中发现所有相似的代码。另一方面代码克隆也赋能了我们的其他智能服务,比如缺陷检测、代码质量分析等等。但是,Type3级大部分都是基于Token或者语法树的,我们希望在保证效率的情况下,能更好的向Type4靠拢。
*映农
微软在这方面做了不少工作。一个是在VisualStudio开发环境集成了微软研究院关于克隆代码检测的研究成果,使得全世界任何使用VisualStudio的开发者都可以收益:
(1)随时监测自己程序中的克隆代码,并辅以可视化的方式使得程序员能够快速判断一段克隆代码是否有潜在bug,是否有潜在的重构的必要。
一个是微软研究院和微软安全部门合作,索引了微软所以重要产品的源代码,基于索引,提供克隆代码搜索服务。价值在于,对于安全部门检测到的任何安全漏洞,通过克隆代码搜索,保证全公司重要产品中潜在的克隆漏洞都会被迅速发现,从而杜绝零日漏洞。
包晓晶
在我们公司,我们基本是在使用软件产品线的思路,通过强调模块复用来规避代码克隆的问题,包括类库/构件以及运行态的服务化或者微服务接口的复用。有自顶向下的服务和构件的设计,或者是自下而上的从现有代码中的抽取。单纯从代码克隆检测和分析方面做的工作还是比较少的,主要还是工具和框架层面的支持,最近也一直和彭老师这边合作对我们现有的代码进行分析,能让我们从这个角度来取得一些进展。也向其他各位老师多学习。
刘扬
1基于源码的克隆分析,主要是跟林云,xingzhenchang老师和彭老师团队的合作
Clonepedia:SummarizingCodeClonesbyCommonSyntacticContextforSoftwareMaintenance.
DetectingandSummarizingDifferencesacrossMultipleInstancesofCodeClones,36thInternationalConferenceonSoftwareEngineering(ICSE)
2基于二进制代码的漏洞检测是跟中科大的薛银杏教授合作的。
BinGo:Cross-ArchitectureCross-OSBinarySearch,ACMSIGSOFTInternationalSymposiumontheFoundationsofSoftwareEngineering(FSE)
AccurateandScalableCross-ArchitectureCross-OSBinaryCodeSearchwithEmulation,IEEETransactionsonSoftwareEngineering(TSE18).
3最近我们在做code克隆的diff分析,包括源码和二进制代码。
CLDIFF:GeneratingConciseLinkedCodeDifferences,The33rdIEEE/ACMInternationalConferenceonAutomatedSoftwareEngineering(ASE),
SPAIN:SecurityPatchAnalysisforBinaries-TowardsUnderstandingthePainandPills,The39thInternationalConferenceonSoftwareEngineering(ICSE),
目前正在做的几个方向:
1)基于函数级别的C源码和C二进制代码漏洞数据收集和克隆检测。
2)Apk的Cbinary和Jar,JS的漏洞克隆检测。
3)代码diff的分析和代码兼容性分析。
4)漏洞克隆大数据分析。
张刚
这个问题我算是回答过了。单独的工具挺多的,大家前面都提到了。IDE内建的工具也挺多,刚才也说了一下。现在我最关心价值角度的准确率。一堆不准确的检测结果,会隐藏真正的问题。
讨论环节:
张刚:误报率不是真的“误报”,而是价值。很多克隆都是低价值的。我不止一次的在stackoverflow上看到有人问如何关掉IDE中的重复功能。这是大数据发挥价值的领域。我们也在做一些相关的工作。
*映农:误报率不是真的“误报”,而是误报没有必要采取措施的“无害”克隆。完全同意。需要报的是有需要当下就采取行动的克隆。比如,有bug,或可以也必须立即重构。这个是很难的。需要学术界的支持
刘扬:AccurateandScalableCross-ArchitectureCross-OSBinaryCodeSearchwithEmulation,IEEETransactionsonSoftwareEngineering(TSE18).我们这篇就是做binarytype4的检测的。
吴毅坚:如果二进制能做出来type4的话,源代码也许问题不是太大?我感觉现在很多是因为二进制不好做,大家才做源代码了。刘扬:道理是一样的,源码应该更好做。我这边有个年轻老师liyi在做equivalencechecking。非常不错的进展QUESTIONV
在代码克隆检测和分析的基础上,软件企业还需要对代码克隆(包括内部以及外部的代码克隆)进行全面和系统性的管理,例如来源追踪、演化过程及其一致性维护等。
在代码克隆管理方面,您所在的企业或者研究组以及所了解的其他企业进行了哪些实践和探索,取得了哪些进展和成果,还存在哪些痛点以及需要进一步解决的问题?
*泥
一些挑战和设想。
1克隆检测匹配算法多维度数据应用,代码分析+NLP,应用多维度的数据,代码语法树,符号等以外的更多维度的数据。如注释信息,提交人,提交频度,开发任务,历史信用,执行日志,运行输出等。
2提升能够处理的代码规模(亿)和分析速度(30秒反馈),从离线处理变成在线分析。找得准准,找得快,得到程序员认可。
3同配置管理,IDE,静态检查,代码review,重构,代码提交,合规检查和发布系统的结合。
息羽
代码克隆检测技术在阿里的应用的一个方向是推动代码分享文化,阿里鼓励代码有秩序的分享,所谓秩序就是可跟踪、可溯源、可授权,我能知道我的代码被谁引用到了哪个项目中,用来做了什么,能让我间接的成为项目的贡献者,并且能授权将项目代码开源出去。这些方面目前还有一些难度,是我们未来期望努力的一个方向,特别是如何去识别代码是从哪里克隆来的,需要一个系统的监控体系才行。
*映农
我来谈两个痛点。
第一,如何检测并报告actionable的克隆代码是一个没有完全解决的问题。一段克隆代码,值得现在重构吗?有潜在bug吗?这些是开发者真正关心的问题,仅仅检测克隆代码并报告还远远不够,还需要深入研究可重构性,结合bug查找。
第二,如何把克隆代码的检测和管理无缝集成到源码管理的大框架中,是一个我认为一直没有解决好的问题。刚才也提到过。一个专门针对克隆代码的管理工具很难被大规模应用。需要在多个环节,codeauthoring,codereview,build,等等多个环节把关。
包晓晶
好的。对于代码克隆的检测分析,我们还处于刚起步阶段,现在预想的内部推广路径是首先完成方法论让团队形成共识,然后从流程、工具方面进行规范,找项目组进行试点,后续会进行全公司的推广工作,并数据积累形成全生命周期的规划、分析、跟踪、反馈和改进体系。
刘扬
这个问题我多说两句。在彭老师的大力支持下,最近我们开始