精华内容
下载资源
问答
  • 代码减少冗余工具
    千次阅读
    2022-02-11 08:48:24

    市场上静态代码扫描工具百花齐放,种类繁多,本文通过相关云厂商咨询、互联网峰会资料查阅和主流技术网站检索得出初步结论,和大家分享讨论。

    1、spotbugs/findbugs(java)

    SpotBugs (开源)是一个使用静态分析来查找 Java 代码中的错误的程序。它是自由软件,根据GNU 宽通用公共许可证的条款分发。
    SpotBugs 是FindBugs(现在是一个废弃的项目)的一个分支,在其社区的支持下从它停止的那一点开始。详情请查看官方手册。

    2、TScanCode(C/C++、C#、Lua)

    TscanCode(腾讯开源)是一款静态代码扫描工具,TscanCode旨在助力开发与测试人员从代码层面挖掘问题,将那些长期困扰项目的诸如空指针宕机等问题,扼杀于萌芽阶段。支持用户根据不同需求自定义配置检查项,有极强的扩展性和可维护性。平均扫描速度10W行/分钟。

    3、pclint(C/C++)

    由Gimpel Software公司提供(付费)。X PC-lint 是一个强大的静态分析工具,它将检查您的 C/C++ 源代码并发现错误、故障、不一致、不可移植的结构、冗余代码等等。它查看多个模块,因此享有编译器所没有的视角。

    4、Cppcheck(C/C++)

    支持图形界面和命令行;Cppcheck是 C/C++ 代码的静态分析工具(开源) 。它提供独特的代码分析来检测错误,并专注于检测未定义的行为和危险的编码结构。目标是减少误报。Cppcheck 旨在能够分析您的 C/C++ 代码,即使它具有非标准语法(在嵌入式项目中很常见)。

    5、Klocwork(C、C++、C#、Java、JavaScript )

    国内使用较广泛的分析工具(付费);适用于 C、C++、C#、Java、JavaScript 和 Python 的Klocwork 静态代码分析和SAST工具可识别软件安全性、质量和可靠性问题,帮助强制遵守标准。

    6、Coverity Prevent(C/C++、C#、JAVA)

    提供多种辅助工具,专长于最准确的找到最严重和最难检测的缺陷(付费)。

    7、ESLint(JavaScrip、NodeJs)

    ESLint 是一个开源的 JavaScript 代码检查工具,由 Nicholas C. Zakas 于2013年6月创建。代码检查是一种静态的分析,常用于寻找有问题的模式或者代码,并且不依赖于具体的编码风格。对大多数编程语言来说都会有代码检查,一般来说编译程序会内置检查工具。

    8、Flake8(Python)

    它综合以下三者的功能,在简化操作的同时,还提供了扩展开发接口。(开源
    PyFlakes:静态检查Python代码逻辑错误的工具。
    pep8: 静态检查PEP 8编码风格的工具。
    Ned Batchelder’s McCabe script:静态分析Python代码复杂度的工具。

    9、Pylint(Python)

    Pylint 是一种检查 Python 代码错误、尝试执行编码标准并查找代码异味的工具(开源)。它还可以查找某些类型错误,可以推荐有关如何重构特定块的建议,并可以为您提供有关代码复杂性的详细信息。

    10、PhpMetrics(PHP)

    PhpMetrics 分析您的 PHP 代码并提供 HTML、JSON、CSV ......关于复杂性、依赖关系、耦合、违规等的报告。(开源

    11、golangci-lint(go)

    GolangCI-Lint是一个lint聚合器(开源),它的速度很快,平均速度是gometalinter的5倍。它易于集成和使用,具有良好的输出并且具有最小数量的误报。而且它还支持go modules。最重要的是免费开源。

    12、sonarqube(多种)

    sonar是一款静态代码质量分析工具(开源),支持Java、Python、PHP、JavaScript、CSS等25种以上的语言,而且能够集成在IDE、Jenkins、Git等服务中,方便随时查看代码质量分析报告;

    更多相关内容
  • java开发之消除冗余代码的3种方法

    千次阅读 2020-05-13 21:00:24
    同,如果用代码来实现蛋糕制作流程,要写大量重复代码,容易产生BUG,我们可以使用工厂模式和模板方法模式来避免重复。 首先定义一个蛋糕类Cake: @Data public class Cake { // 蛋糕名称 String cakeName; ...

    一.利用工厂模式+模板方法模式

    我们以做蛋糕为例来演示如何消除重复代码。

    假设我们要做3种不同口味的蛋糕,分别是抹茶,可可和草莓蛋糕,实际上3种蛋糕的制作方法是极其相似的,只有添加的粉剂不

    同,如果用代码来实现蛋糕制作流程,要写大量重复代码,容易产生BUG,我们可以使用工厂模式和模板方法模式来避免重复。

    首先定义一个蛋糕类Cake:

    @Data
    public class Cake {
    	// 蛋糕名称
    	String cakeName;
    	
    	Integer sugar;
    	
    	Integer eggs;
    	
    	Integer flour;
    	
    	// 添加剂(可可粉,抹茶粉,草莓)
    	String supplement;
    }

    再定义一个制作蛋糕的抽象父类:

    @Service
    public abstract class AbstractCakeService {
    
        //处理做蛋糕的重复逻辑在父类实现
        public Cake doCake(){
    	    Cake cake = new Cake();
    	    cake.setEggs(2);
    	    cake.setFlour(250);
    	    cake.setSugar(30);
    	    //让子类实现不同的蛋糕处理
    	    addOtherMaterial(cake);
    	    return cake;
        }
    	
        // 不同属性的赋值留给子类实现
        protected abstract void addOtherMaterial(Cake cake);
        
    }

    我们定义3个不同的子类:抹茶蛋糕,可可蛋糕,草莓蛋糕制作,他们都继承抽象的父类AbstractCakeService,分别为

    TeaCakeService,CocoaCakeService,StrawberryCakeService。

    抹茶蛋糕TeaCakeService的实现:

    @Service(value = "TeaCakeService")
    public class TeaCakeService extends AbstractCakeService{
    
    	@Override
    	protected void addOtherMaterial(Cake cake) {
    		cake.setCakeName("抹茶蛋糕");
    		cake.setSupplement("抹茶粉");
    		System.out.println("当前正在制作好吃的抹茶蛋糕");
    	}
    
    }

    可可蛋糕CocoaCakeService的实现: 

    @Service(value = "CocoaCakeService")
    public class CocoaCakeService extends AbstractCakeService{
    
    	@Override
    	protected void addOtherMaterial(Cake cake) {
    		cake.setCakeName("可可蛋糕");
    		cake.setSupplement("可可粉");
    		System.out.println("当前正在制作好吃的可可蛋糕");
    	}
    
    }

    草莓蛋糕CocoaCakeService的实现: 

    @Service(value = "StrawberryCakeService")
    public class StrawberryCakeService extends AbstractCakeService{
    
    	@Override
    	protected void addOtherMaterial(Cake cake) {
    		cake.setCakeName("草莓蛋糕");
    		cake.setSupplement("新鲜草莓");
    		System.out.println("当前正在制作好吃的草莓蛋糕");
    	}
    
    }

    3种蛋糕制作都叫 XXXCakeService,那我们就可以把蛋糕类型字符串拼接 CakeService构成 Bean 的名称,然后利用 Spring 的

    IoC 容器,通过 Bean 的名称直接获取到 AbstractCakeService,调用其 doCake方法来实现不同蛋糕的制作调用,这就是借助

    Spring 容器实现了工厂模式。

    调用的控制层代码如下:

    @RestController
    public class cakeController {
    	
    	@Autowired
    	private ApplicationContext applicationContext;
    
    	@GetMapping("doCake")
    	public Cake doCake(@RequestParam("supplement") String supplement) {
    		AbstractCakeService cake = (AbstractCakeService) applicationContext.getBean(supplement + "CakeService");
    		return cake.doCake();
    	}
    }

    传入需要的添加剂,实现蛋糕的制作:

    这样一来,我们利用工厂模式 + 模板方法模式,不仅消除了重复代码,还避免了修改既有代码的风险。这就是设计模式中的开闭

    原则:对修改关闭,对扩展开放。

    git代码实现路径:

    https://github.com/jichunyang19931023/dailyDemo/tree/master/cake

     

    二.利用注解 + 反射消除重复代码

    假如我们要和外部系统进行接口服务对接,需要一个接口来输出接口的定义和传参等信息,此时我们可以利用注解+反射的机制来解决这个问题。

    如果有一个创建票据的接口需要生成API的信息,要实现接口逻辑和逻辑实现的剥离,首先需要以 POJO 类(只有属性没有

    任何业务逻辑的数据类)的方式定义所有的接口参数,如下所示:

    @Data
    public class CreateTicketAPI {
    	// 用户名
    	String userName;
    	// 密码
    	String password;
    	// 当前时间的时间戳
    	Long currentTime;
    }

    我们可以通过自定义注解为接口和所有参数增加一些元数据。如下所示,我们定义一个接口的注解 API,包含接口接口说明, URL 地址和请求方式:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Inherited
    public @interface API {
        String desc() default "";
        String url() default "";
        String type() default "GET";
    }

    然后,我们再定义一个自定义注解 @APIField,用于描述接口的每一个字段规范,包含参数的可否为空、类型和说明三个属性:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @Documented
    @Inherited
    public @interface APIField {
        // 可否为空
        boolean isRequired() default false;
        // 参数类型
        String type() default "";
        // 参数说明,备注
        String remark() default "";
    }

    修改原始的POJO 类,补充接口和每个参数字段的元数据(也就是对应的属性相关信息),继承的 AbstractAPI 类是一个空实

    现,这个案例中的接口并没有公共数据可以抽象放到基类:

    @API(url = "/creatTicket", desc = "创建票据接口", type = "GET")
    @Data
    public class CreateTicketAPI extends AbstractAPI{
    	
    	@APIField(isRequired = true, type = "String", remark = "用户名称")
    	String userName;
    	
    	@APIField(isRequired = true, type = "String", remark = "密码")
    	String password;
    	
    	@APIField(isRequired = false, type = "Long", remark = "当前时间的时间戳")
    	Long currentTime;
    }
    

    以上,我们通过注解实现了对 API 参数的描述。接下来,我们再看看反射如何配合注解实现接口属性和参数说明:

    @Slf4j
    @Service
    public class APIService {
    
    	public JSONObject apiCreate(AbstractAPI api){
    		JSONObject result = new JSONObject();
    		// 从API注解获取请求说明
    		API apiObj = api.getClass().getAnnotation(API.class);
    		result.put("apiDesc", apiObj.desc());
    		result.put("apiUrl", apiObj.url());
    		result.put("apiType", apiObj.type());
    		
    		JSONArray apiParams = JSONUtil.createArray();
    		Arrays.stream(api.getClass().getDeclaredFields()) // 获得所有字段
    				.filter(field -> field.isAnnotationPresent(APIField.class)) // 查找标记了注解的字段
    				.peek(field -> field.setAccessible(true)) // 设置可以访问私有字段
    				.forEach(field -> {
    					JSONObject paramObj = new JSONObject();
    					// 获得注解
    					APIField apiField = field.getAnnotation(APIField.class);
    					Object value = "";
    					try {
    						// 反射获取字段值
    						value = field.get(api);
    					} catch (IllegalAccessException e) {
    						log.error("反射获取字段值发生异常", e);
    					}
    					paramObj.put("paramName", field.getName());
    					paramObj.put("paramType", apiField.type());
    					paramObj.put("isRequired", apiField.isRequired());
    					paramObj.put("remark", apiField.remark());
    					paramObj.put("paramValue", value);
    					apiParams.add(paramObj);
    				});
    		result.put("apiParams", apiParams);
    		return result;
    	}
    }

    最后控制层进行调用:

    @RestController
    public class APIController {
    	
    	@Autowired
    	private APIService apiService;
    
    	@GetMapping(value = "/getApi")
        public JSONObject getApi(String userName, String password, Long currentTime) {
    		CreateTicketAPI ticketAPI = new CreateTicketAPI();
    		ticketAPI.setUserName(userName);
    		ticketAPI.setPassword(password);
    		ticketAPI.setCurrentTime(currentTime);
    		return apiService.apiCreate(ticketAPI);
        }
    }

    许多涉及类结构性的通用处理,都可以按照这个模式来减少重复代码。反射给予了我们在不知晓类结构的时候,按照固定的逻辑

    处理类的成员;而注解给了我们为这些成员补充元数据的能力,使得我们利用反射实现通用逻辑的时候,可以从外部获得更多我

    们关心的数据。

    git代码实现路径:

    https://github.com/jichunyang19931023/dailyDemo/tree/master/api

    三.利用属性拷贝工具消除重复代码

    对于三层架构的系统,考虑到层之间的解耦隔离以及每一层对数据的不同需求,通常每一层都会有自己的 POJO 作为数据实体。

    比如,数据访问层的实体一般叫作 DataObject 或 DO,业务逻辑层的实体一般叫作 Domain,表现层的实体一般叫作 Data

    Transfer Object 或 DTO。如果手动写这些实体之间的赋值代码,同样容易出错,所以我们可以利用属性拷贝工具来消除重复代

    码。

    使用类似 BeanUtils 这种 Mapping 工具来做 Bean 的转换,copyProperties 方法还允许我们提供需要忽略的属性:

    
    ComplicatedOrderDTO orderDTO = new ComplicatedOrderDTO();
    ComplicatedOrderDO orderDO = new ComplicatedOrderDO();
    BeanUtils.copyProperties(orderDTO, orderDO, "id");
    return orderDO;

    或者可以使用一个很棒的工具包hutool来实现,下面是官方文档网址,支持不同类型的拷贝,十分方便:

    https://www.hutool.cn/docs/#/

     

    展开全文
  • 好的代码一定是整洁的,并且能够帮助阅读的人快速理解和定位。好的代码可以加快应用的开发迭代速度,不必花过多的时间来修复 bug 和完善代码。好的代码不但能够使得新的项目成员更容易加入项目,...

    好的代码一定是整洁的,并且能够帮助阅读的人快速理解和定位。好的代码可以加快应用的开发迭代速度,不必花过多的时间来修复 bug 和完善代码。好的代码不但能够使得新的项目成员更容易加入项目,同时方便项目组成员快速做好 Back up。好的代码便于促进团队间交流合作提升开发效率。

    代码质量评价标准

    有编码经验的人对代码都有一定的“鉴赏力”,能够凭感觉给出代码好坏的主观评价。但是这种凭感觉的方式太过个性随意,所谓仁者见仁智者见智,很难达成共识,那有没有一种公认的标准来鉴定代码质量呢?

    答案是有的。这里简单分享当下较常用的评价标准,其中包括:编码规范、可读性、可维护性、重复度及可测试性。

    编码规范

    主要包含是否遵守了最佳实践和团队编码规范,是否包含可能出问题的代码,以及可能存在安全的漏洞。编码规范有助于提高团队内协助的效率以及代码的可维护性。

    可读性

    Code Review 是一个很好的测验代码可读性的手段。如果你的同事可以轻松地读懂你写的代码,那说明你的代码可读性很好;反之则说明你的代码可读性有待提高了。遵守编码规范也能让我们写出可读性更好的代码。

    可维护性

    代码的可维护性是由很多因素协同作用的结果。代码的可读性好、简洁、可扩展性好,就会使得代码易维护;更细化地讲,如果代码分层清晰、模块化好、高内聚低耦合、遵从基于接口而非实现编程的设计原则等等,那就可能意味着代码易维护。除此之外,代码的易维护性还跟项目代码量的多少、业务的复杂程度、利用到的技术的复杂程度、文档是否全面等诸多因素有关。

    重复度

    遵守 Don’t Repeat Yourself 原则,尽量减少重复代码的编写,复用已有的代码。对项目定期进行代码重复度检测是一个很有意义的事,可以帮助开发人员发现冗余代码,进行代码抽象和重构。重复的代码一旦出错,意味着加倍的工作量和持续的不可控。如果代码中有大量的重复代码,就要考虑将重复的代码提取出来,封装成公共的方法或者组件。

    可测试性

    代码可测试性的好坏,同样可以反应代码质量的好坏。代码的可测试性差,比较难写单元测试,那基本上就能说明代码设计得有问题。

    除此之外还有很多代码质量评价标准。我们需要一些取舍,选取部分大家有共识的规则定义团队好的代码标准。

    代码质量维度

    当前版本通过 @iceworks/doctor 从 5 个维度对代码进行评分:

    1. 最佳实践:通过 @iceworks/eslint-plugin-best-practices 分析项目,提出符合当前工程特征(对 ice 和 Rax项目友好)的最佳实践及阻塞问题发布卡口,帮助开发者优化项目性能,避免潜在 bug 。

    2. 安全实践:通过 @iceworks/eslint-plugin-security-practices 扫码代码检测工程中可能存在的安全风险,包含 url 、敏感成词、明文账密信息及 npm 包证书检测,降低项目安全风险,守卫项目安全。

    3. 阿里代码规范:这一维度主要反馈开发人员对于 eslint-config-ali 阿里开发规约的遵守程度。

    4. 可维护度:通过 typhonjs-escomplex 对文件进行扫码,得出每个文件的可维护度,可读性及复杂度评分。针对得分较差的文件可以进行深度分析帮助开发者更好的重构复杂代码。

    5. 重复度:通过 jscpd 计算重复出现的代码区块占比,计算出 clone 分数。并逐一列举重复的代码,方便开发者快速定位重复代码,将其封装成公共的方法或者组件。

    根据上述 5 个维度通过加权平均的方式计算项目质量分,并根据木桶效应,在计算得分的过程中加大了最低分的权重,得出最终项目质量评分。

    项目地址

    github地址:https://github.com/ice-lab/iceworks/tree/master/

    推荐几款代码质量检测工具:

    然后说说工具的问题。我用过的开源、商业代码质量工具没少说也有个二三十种( V 站除了同行应该没人比我多了。。。吧)。这些工具如果按照规则类型划分,可以看做两类。一类安全,也就是检查安全问题,比如 NullPointer、SQL Injection、Data Race,他们会影响程序的安全运行;一类是规约,简单来说就是 code style。不过考虑到很多规则其实两者兼具,我就简单的按语言划分好了。(都是开源的)

    c/c++:

    clang-tidy http://clang.llvm.org/extra/clang-tidy

    CSA https://clang-analyzer.llvm.org

    cppcheck https://github.com/danmar/cppcheck

    cpplint https://github.com/google/styleguide

    phasar https://github.com/secure-software-engineering/phasar

    这里面比较推荐 clang-tidy,虽然规则不多,但是规则编写简单,只要你对 C++有足够了解,可以定制出十分丰富的内容

    java:

    google-java-format https://github.com/google/google-java-format

    find-sec-bugs https://find-sec-bugs.github.io

    spotbugs https://spotbugs.github.io

    pmd https://github.com/pmd/pmd

    p3c https://github.com/alibaba/p3c

    soot https://sable.github.io/soot

    spotbugs 和 pmd 都是比较优秀的工具,前者有 find-sec-bugs 这样的插件。而后者,ali 的 p3c 规则集就是基于 pmd 实现的。此外 pmd 是一个针对多种语言的框架,内容十分丰富。这两者国际化和文档都做的非常好。而 soot 本质上一个 jvm bytecode 的优化框架,但同样可以基于此做出各种工具,不过考虑到它复杂的内容,emmmm...

    其他:

    python https://github.com/PyCQA/pylint

    kotlin https://github.com/arturbosch/detekt

    JS/TS https://github.com/eslint/eslint

    Rust https://github.com/rust-lang/rust-clippy

    shell https://github.com/koalaman/shellcheck

    Multiple languages https://github.com/facebook/infer

    Multiple languages https://github.com/github/semantic

    我列举的都是我觉得有用的并且目前处于活跃状态的项目,大家无聊的话可以看看。还有一个专门介绍静态分析工具的仓库https://github.com/mre/awesome-static-analysis

    再然后对于工具的使用。对于工具大家都知道,不用等于没用。所以一般的解决办法都是融入流程,最简单的像 Unittest 一样,编译完成后跑一遍。并入 CI 流程也是普遍做法,代码入库前扫描成功才允许合并,这样同时还可以保证 code format 的问题。除此之外,减少这类工具的 report 数量也是重点。过于繁多的报告(尤其是项目早期开发的时候)往往不利于发现真正有价值的问题,也不利于修复。所以熟悉工具的规则和配置,少报无关问题是工具使用的关键。

    简单说就这么多,如果感兴趣我有空可以开个系列,专门介绍代码静态分析的技术、使用问题

    号称中国最好的静态分析工具(将来就是世界最好)

    https://www.sourcebrella.com/

    对标国际厂商比如 Coverity、fortify、checkmax,我们一点不虚,甚至在技术上还有优势( PLDI、ICSE 最近几年都有论文) 

    展开全文
  • OCLint- //oclint.org OCLint是一种静态代码分析工具,可以通过检查C,C ++和Objective-C代码来提高质量并减少缺陷。 它寻找编译器看不到的潜在问题,例如: 可能的错误-if / else / try / catch / finally语句为空...
  • OCLint是一种静态代码分析工具,可以通过检查C,C ++和Objective-C代码来提高质量并减少缺陷。 它寻找编译器看不到的潜在问题,例如: 可能的错误-if / else / try / catch / finally语句为空 未使用的代码-未使用的...
  • 大量减少代码量-如果您需要使用AST对代码进行升级,改造,分析,快用gogoAST帮你扩展繁琐冗余代码,专注于你的核心逻辑。不需要遍历,像剥洋葱一样一层一层的对比,操作,构造ast异步。降低理解成本-甚至不需要...
  • 冗余代码检测与分析

    2017-10-09 18:03:00
    \\t为了检测冗余代码,作者开发了一个工具,使用Roslyn创建C#源码抽象语法树。作者使用包括Roslyn和MSBuild在内的多个GitHub项目对这个工具进行了训练;\\t检测到冗余代码可以手动删除或添加...
    \

    本文要点

    \\
    • 代码冗余的原因多种多样,从未使用的变量到未完成的变更,再到废弃的代码;\\t
    • 冗余代码会产生一系列的影响,包括源代码臃肿、可靠性及可维护性降低。在某些情况下,死代码也会影响性能;\\t
    • 为了检测冗余代码,作者开发了一个工具,使用Roslyn创建C#源码抽象语法树。作者使用包括Roslyn和MSBuild在内的多个GitHub项目对这个工具进行了训练;\\t
    • 检测到冗余代码可以手动删除或添加注释,也可以使用一种自动化工具。使用特性分支有助于防止冗余代码检入主代码分支。\
    \\

    导言

    \\

    前段时间,我开发了一款工具,分析源代码中的依赖关系。它使用Roslyn创建C#源代码抽象语法树使用libclang创建C++源代码抽象语法树。为了验证它是否可以取得预期效果,我接下来实现了识别未使用方法的功能。结果显示,C#代码解析比C++代码解析准确得多,因此,我选择把重点放在C#分析器的进一步开发和其他人开发的更复杂的C#代码上。

    \\

    起初,该工具会标记出冗余方法所在的行,在弄清楚问题范围之后,我实现了自动删除那些行的选项。一个典型的分析过程会多次执行这个工具,尽可能地修剪源代码树。接下来是多个变更还原循环,以便可以成功地构建并通过测试。失败的原因是工具行为异常或者已知的局限性,例如,反射或代码契约。

    \\

    我选择了多个自己用过而又想回馈的C#项目,用它们的GitHub库训练了这个工具。最后,我向社区提交了pull request,请求他们讨论我在自己的分支里做的变更。由于这个工具很苛刻,而我又是第一次在网上与人交流,不懂技巧,所以希望我没有冒犯太多的人。在向社区做贡献及参与后续讨论的过程中,我对问题的理解更深入了,本文旨在将我的所得回馈给更广泛的社区。

    \\

    分析过的GitHub项目

    \\

    由JB Evain编写的Mono.Cecil可以将.NET代码反编译成C#。根据建议,只有36行代码需要删除,经过审核,JB选择单独添加部分变更,而不是合并分支。

    \\

    Automatic Graph Layout是微软官方的一个项目,由Lev Nachmanson、Sergey Pupyrev、Tim Dwyer、Ted Hart和Roman Prutkin开发,用于绘制图和有向图,Visual Studio也用它显示各种交互图。Pull request要求删除4674行代码,其中有一些和SilverLight有关(已于2015年宣布停用)。不经过修改或讨论,分支就被合并了进去。

    \\

    Roslyn是一个现代化的C#编译器,由.NET基金会的一个团队负责维护。在这个例子下,Pull request要求删除18364行代码,这引发了有益的讨论,并产生了下面讨论的大多数分类。显然,这个分支太大了,无法合并,取而代之,多个单独的议题被提了出来。

    \\

    MSBuild是微软官方的一个项目,Visual Studio的用户应该比较熟悉。根据分析,我提交了删除3722行代码的pull request,遗憾的是,其团队当时没有余力审核我提出的变更建议。

    \\

    最后分析的是.NET Core基础库里的System.XML程序集。这些库由.NET基金会负责维护,为了删除死代码,其团队发布了一条问题追踪信息。该问题的解决方法是逐个修剪程序集(通常被称为死代码消除),然后比较未修剪程序集和已修剪程序集之间的差异,从而确定哪些编译代码被删除了。通过这些差异可以知道哪些源代码被删除了,这项工作通常是由志愿者社区承担。

    \\

    鉴于只用该工具抽样分析了五个项目,得出任何结论都是不明智的,尤其是在缺少可靠的统计数据的情况下:

    \\
     Mono.CecilMSAGLRoslynMSBuildCoreFX (System.XML)
    已删除364674183643722427
    初次提交时间2010/04/122015/02/222014/03/182015/03/122014/11/08
    作者(主要)39 (1)25 (4)285 (31)90 (6)526 (29)

    鉴于其悠久的历史,MSBuild的初次提交时间值得注意。仅数一下作者的数量而不评估他们的贡献几乎可以肯定是没有意义的,因此我大致估计了主要的贡献者。说到这里,我推测:

    \\
    • 新开发的项目比成熟项目冗余代码多 \\t
      • 编写代码时假定将来会需要\\t\t
      • 测试少,相应的,发现的Bug就少\\t
      \\t
    • 团队越大制造的冗余代码越多 \\t
      • 沟通成本会随团队规模的扩大而呈几何级数上升,参见《人月神话》\\t
      \

    测试结果分类

    \\

    该工具测试冗余方法,和任何测试一样,分析有成功和失败之分。

    \\

    真负:

    \\
    • 代码有用\

    假负:

    \\
    • 测试代码 \\t
      • 测试的功能只有测试使用。这可能是TDDBDD过程的产物,在这种情况下,它可能用来追溯不需要或者未满足的需求。\\t
      \\t
    • 死代码 \\t
      • 虽然被调用了,但代码什么都没做,这种调用可以删除。\\t\t
      • 可以是重复代码。\\t\t
      • 注意,可以认为已废弃代码距离死代码只差一步。\\t
      \

    真正:

    \\
    • 故意放弃的开发 \\t
      • 方法已经添加,但环境变了,这些方法不会再使用了\\t
      \\t
    • 未完成的变更 \\t
      • 代码已变更,有些方法所有引用都删除了,但后续提交时没有将其考虑在内。这种代码有时候称为oxbow代码。它可能是重构的意外产物。\\t
      \\t
    • 未使用的变量 \\t
      • 但愿IDE会生成编译器警告和/或报告。\\t
      \

    假正:

    \\
    • 工具缺陷 \\t
      • 该工具没有检测使用反射代码契约的代码,它依赖构建或测试过程的错误来检测这些代码。\\t
      \\t
    • 回归 \\t
      • 在开发过程中,经过修改,一个方法不再调用标识为死亡的方法,此时,这种情况就会出现。显然,没有测试识别这种回归。\\t
      \\t
    • 缺少条件编译 \\t
      • 通常,这是指缺少#if DEBUG保护。Roslyn已经用于Release构建,这个过程会识别相应二进制文件中的代码膨胀。\\t
      \\t
    • 无意放弃的开发 \\t
      • 这是在特定的测试数据下发现的,但没有相应的测试。通常来说,我希望这是一个暂时的问题,随着代码增加会自然消失。\\t
      \\t
    • 在子系统中未使用 \\t
      • 分析低效的代码,找出使用该方法的地方。虽然反射也会导致这个问题,但这主要出现在公共方法分析时。一个常见的例子是执行测试辅助功能的时候没有相应的测试代码,不过,那会抛出一个设计问题,定位到测试辅助代码。\\t
      \\t
    • 仅限调试器使用的方法 \\t
      • 在附加了调试器时(可能是Release构建),有些项目会有方法打印出状态。这些方法应该以某种方式标记出来,那样就不用分析它们了。\\t
      \

    需要注意,工具失败不一定是因为推理不足。其中有些情况是其他工具的处理范畴,如编译器警告应该标记部分问题,重复代码检测器也有用。

    \\

    冗余代码的影响

    \\

    假负和真正都可以视为YAGNI的实例,这就需要我们注意以下事项:

    \\
    • \\t

      臃肿的源代码

      \\\t
      • 以前,我遇到过文本编辑器无法打开大文件的情况。\\t\t
      • 开发人员的认知受限于大脑中可以同时容纳的独立实体的数量,通常认为是7个,因此,删除方法可以提升推理能力。\\t\t
      • 所有开发人员用来阅读和理解源代码的时间很可能都是浪费。\\t\t
      • 现代IDE通常都是从源代码生成抽象语法树,因此,冗余代码降低了它们的速度。\\t
      \\t
    • \\t

      臃肿的可执行文件

      \\\t
      • 在手机上,这尤其是个问题,为了释放存储,升级会删除应用,最终,当功能受到过度损害,就不得不升级设备了。\\t
      \\t
    • \\t

      臃肿的运行时

      \\\t
      • 为黑客提供了更大的攻击面,让他们发现安全问题。\\t\t
      • 部分面向嵌入式设备的应用程序会在启动时分配所有的动态内存,因此,冗余代码会减少可用堆的大小。\\t
      \\t
    • \\t

      降低性能

      \\\t
      • 在特定的情况下,死代码执行会浪费处理器周期。\\t
      \\t
    • \\t

      降低可靠性

      \\\t
      • 在特定的情况下,死代码执行可能导致崩溃。\\t
      \\t
    • \\t

      降低可维护性

      \\\t
      • 如果执行到冗余代码时停下了,那么行为将不可预测,如Knight Capital损失了4.4亿美元。\\t\t
      • 代码覆盖率可能会因假负而升高,因假正而降低。\\t\t
      • 不必要的测试会降低测试套件的执行速度。\\t\t
      • 静态分析工具不得不处理更多的代码,并因此效率降低。\\t\t
      • 软件的设计/架构看起来比实际情况复杂。考虑到冗余代码会导致各种各样的问题,最好是将其视为代码异味。\\t
      \

    管理已有的冗余代码

    \\

    处理冗余代码有四种方法:

    \\
    • \\t

      忽略

      \\\t
      • 虽然会增加维护成本,但至少可以通过编译。\\t\t
      • 不推荐。\\t
      \\t
    • \\t

      自动从可执行文件中移除

      \\\t
      • 编译型语言在链接器中使用任意一种死代码移除选项移除。\\t\t
      • 动态语言使用Tree Shaking在运行时移除。\\t\t
      • 也不推荐。\\t
      \\t
    • \\t

      屏蔽

      \\\t
      • 注释掉或者使用预编译指令。\\t\t
      • 使用IDE提供的代码/注释折叠避免看到它。\\t
      \\t
    • \\t

      删除

      \\\t
      • 借助源代码控制保留旧版本供参考,可以随时查看。\\t\t
      • 或者你可能永远不再需要它。\\t
      \

    如果要变更源代码,任何变更都需要由熟悉这段代码的人审核,务必保证代码真冗余。

    \\

    管理新开发项目

    \\

    假如目标是在开发过程中不引入新的冗余代码,需要制定什么策略?如果允许部分提交,代码库中可能就会增加暂时冗余的代码。这种情况可以通过特性分支来缓解,只有当测试已覆盖且源代码通过了静态分析才合并进主分支。特性分支的另外一个好处就是在放弃开发后可以将分支保持在未合并状态。

    \\

    关于作者

    \\

    Zebedee Mason 是一名有着25年CAD/CAM/CAE行业经验的数值分析员,他最近搬到了SLAM。多年来,他一直从事与遗留代码库(其中有些在他还是个孩子的时候就已经创建)相关的工作,把许多学术代码改写成商业软件的组件,他甚至还重写了一些原始算法(商业秘密,无法确认)。这种背景使他对软件工具非常了解,他也编写了若干提高生产力的工具,即使以前的开发人员和IT管理人员做出了有用的选择。

    \\

    查看英文原文:Detecting and Analyzing Redundant Code

    展开全文
  • 这个python模块提供了一个基于'tar'的打包器/解压缩器,可以减少打包前的冗余。 有关此模块的信息可以在这里找到: 为什么是“ uppackpack”? 一般而言,经典的压缩工具效果很好。 但是在非常特殊的情况下,...
  • Coverity代码静态检测工具介绍

    千次阅读 2019-08-09 09:51:20
    Coverity代码静态检测工具介绍 ...
  •  本文是一个静态代码分析工具的清单,但是为公司产品需要付费使用。共有37个公司,有些公司包含多个工具。其中27个公司有多语言 工具,1个公司为PHP工具、2个公司为.NET工具、1个公司为Ada工具、4个公司为C++...
  • 静态代码分析工具大全

    千次阅读 2019-12-21 22:53:14
    本文是一个静态代码分析工具的清单,但是为公司产品,需要付费使用。共有37个公司,有些公司包含多个工具。其中27个公司有多语言工具,2个公司为.NET工具、1个公司为Ada工具、4个公司为C++工具、1个公司为Java工具、...
  • 本文代码实现基本按照《数据结构》课本目录顺序,外加大量的复杂算法实现,一篇文章足够。能换你一个收藏了吧?
  • java代码分析及分析工具

    千次阅读 2017-09-15 09:49:32
    代码也就面临着耦合,冗余,甚至杂乱,到最后谁都不敢碰。 作为一个互联网电子商务网站的业务支撑系统,业务复杂不言而喻。从09年开始一直沿用到现在,中间代码经过了多少人的手,留下了多少的坑,已经记不清楚了,...
  • 前端代码审查工具If you are part of a front-end team with several talents (including you), hundreds of commit might be pushed every day. Indeed, no matter the team methodology you use to deliver new ...
  • 《娜璋带你读论文》系列主要是...这篇文章将简单总结Powershell恶意代码检测相关研究,并结合开源工具分享抽象语法树提取过程。希望这篇文章对您有所帮助,这些大佬是真的值得我们去学习,献上小弟的膝盖~fighting!
  • 用 Groovy 减少代码冗余

    千次阅读 2008-12-14 10:35:00
    Groovy 简洁的语法将开发人员从那种需要进行代码编译但却无助于表达 什么 是程序真正想要实现的典型的 Java™ 结构中解放了出来。在实战 Groovy 系列的这一复兴篇中,Groovy 开发人员兼特约专栏作家 J. Scott Hickey...
  • 常用的校验方式有奇偶校验、异或校验、累加和校验(可以看我之前的一篇文章累加和校验算法(CheckSum算法))、循环冗余校验(CRC校验)等等。 奇偶校验、异或校验、累加和校验都比较简单,且易于实现,但是检错能力...
  • 大项目都需要小组中的多人共同完成,但是每个人都有自己的编码习惯,甚至很多都是不正确的。...Checkstyle是一个开源代码分析工具,能够帮助开发人员保证他们的代码遵循一定的代码规范。Checkstyle通过不断地
  • 这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步。这篇文章将详细讲解PowerShell、Powershell恶意代码检测总结及抽象语法树(AST)提取。...
  • Java代码质量检查工具

    万次阅读 2018-05-13 08:27:00
    这样就需要我们需要团队开发,在我们团队中开发人员的经验、代码风格样式都不一致,以及缺乏统一的标准,从而导致我们的整个项目的的代码难以阅读,不便于后期维护。这几天在研究代码质量管理,根据在网上搜集的资料...
  • Android Lint 是 SDK Tools 16(ADT 16)开始引入的一个代码扫描工具,通过对代码进行静态分析,可以帮助开发者发现代码质量问题和提出一些改进建议。除了检查 Android 项目源码中潜在的错误,对于代码的正确性、...
  • 七自由度冗余机械臂运动学逆解与工作空间分析MATLAB实现冗余机械臂基本概念与典型结构冗余机械臂运动学逆解常用方法基于关节角参数化解析逆运动学求解基于臂型角参数化解析逆运动学求解基于臂型角参数化的冗余参数...
  • 受自己阅历和工作经验,项目工期的影响,很多时候我们检查自己的代码很难发现错误(不知道大家有没有这个感觉),或者我们不觉着这块代码有问题,这时候就需要用到“静态代码检测工具”,Andro...
  • 代码插桩

    千次阅读 2019-05-19 09:33:16
    【转载】http://wiki.dzsc.com/info/5081.html 代码插桩是实现覆盖测试的关键技术之一,而高效的插桩技术对于嵌入式软件的测试 来说又是至关重要的。在对CodeTeST 中插桩技术研究的基础上,以G...
  • DevOps系列之 —— 持续开发与集成(四)代码提交及代码评审
  • 在我们打包之后,有很多模块导出的代码,我们可能根本没有用到过,这些冗余代码也跟着一起打包,这不是赤裸裸的浪费带宽嘛。还有我们使用的框架,里面所有的模块我们都用到了?不见得吧。现在,又出现了tree-
  • 代码质量】C++代码质量扫描主流工具深度比较

    万次阅读 多人点赞 2016-05-27 14:16:14
    静态代码分析是指无需运行被测代码,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,找出代码隐藏的错误和缺陷,如参数不匹配,有歧义的嵌套语句,错误的递归,非法计算,可能出现的空指针...
  • 【Tools】Coverity代码静态检测工具

    千次阅读 2018-01-13 16:45:18
    Coverity静态分析工具的功能很强大,超乎我的期望。主要功能如下: 列出不会被执行到的代码列出没被初始化的类成员变量列出没有被捕获的异常列出没有给出返回值的return语句某个函数虽然有返回值,但调用该函数的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 61,482
精华内容 24,592
热门标签
关键字:

代码减少冗余工具