❶ vscode怎么计算代码度量值
vscode代码度量值计算方法指南,助力高效前端开发想知道如何使用vscode计算代码度量值吗?vscode作为流行的前端开发工具,提供了一系列实用功能,其中包括代码度量值计算。本文将由php小编鱼仔深入讲解vscode计算代码度量值的方法,包括具体步骤和技巧。了解这些知识将帮助您优化代码质量,提升开发效率。
操作方法:
1、双击进入软件,点击点击上方菜单栏中的"分析"。
2、接着点击下方选项列表中的"计算代码度量值"。
3、然后点击"用于解决方案"选项。
4、最后在打开的窗口中就可以查看到代码度量值结果。
❷ 什么叫圈复杂度(cyclomatic complexity)为什么它很重要
1、圈复杂度:圈复杂度(Cyclomatic complexity)是一种代码复杂度的衡量标准,在1976年由Thomas J. McCabe, Sr. 提出。
2、重要性:程序的可能错误和高的圈复杂度有着很大关系。
在软件测试的概念里,圈复杂度用来衡量一个模块判定结构的复杂程度,数量上表现为线性无关的路径条数,即合理的预防错误所需测试的最少路径条数。圈复杂度大说明程序代码可能质量低且难于测试和维护。
(2)代码质量度量模型扩展阅读:
下面的列表显示了Visual Studio( VS 2008 Team Suite Edition)计算的代码度量结果:
可维护性指数:计算一个介于 0 和 100 之间的指数值,表示维护代码的相对容易度。值越大表示可维护性越好。该计算基于 Halstead Volume、圈复杂度和代码的行数。按颜色标记的等级可用于迅速发现代码中的故障点。
绿色等级介于 20 和 100 之间,表示代码的可维护性良好。黄色等级介于 10 和 19 之间,表示代码的可维护性中等。红色等级是介于 0 和 9 之间的等级,表示可维护性低。
圈复杂度:衡量代码在结构上的复杂程度。它通过计算程序流中的不同代码路径的数目(例如 if 块、switch case 以及 do、while、foreach 和 for 循环),然后在总数中加 1 来创建。具有复杂控制流的程序需要更多单元测试才能实现良好的代码覆盖率,并且不容易维护。
继承深度:指明扩展到类层次结构根的类定义的数目。层次结构越深,则越难了解特定方法和字段是在何处定义或/和重新定义的。
在类级别,该数目是通过计算继承树中从 0 开始的类型之上的类型数目(不包括接口)来创建的。在命名空间和项目级别,该计算包括命名空间或项目内所有类型的最高继承深度计算。
类耦合:通过参数、局部变量、返回类型、方法调用、泛型或模板实例化、基类、接口实现、在外部类型上定义的字段以及属性修饰来衡量与唯一类的耦合程度。该计算不包括基元类型和内置类型,例如 int32、字符串和对象。
良好的软件设计要求类型和方法应具有较高的内聚力和较低的耦合。耦合较高表示设计难以重用和维护,这是因为它与其他类型之间存在许多依存关系。
代码的行数:指明代码中的大概行数。该计数基于 IL 代码,因此并不是源代码文件中的确切行数。该计算不包括空白、注释、括号以及成员、类型和命名空间的声明。计数过高可能表示某个类型或方法正在尝试执行过多的工作,应予以拆分。还可能表示该类型或方法难以维护。
❸ 一堂如何提高代码质量的培训课
今天这堂培训课讲什么呢?我既不讲Spring,也不讲Hibernate,更不讲Ext,我不讲任何一个具体的技术。我们抛开任何具体的技术,来谈谈如何提高代码质量。如何提高代码质量,相信不仅是在座所有人苦恼的事情,也是所有软件项目苦恼的事情。如何提高代码质量呢,我认为我们首先要理解什么是高质量的代码。 高质液搏量代码的三要素 我们评价高质量代码有三要素:可读性、可维护性、可变更性。我们的代码要一个都不能少地达到了这三要素的要求才能算高质量的代码。 1. 可读性强 一提到可读性似乎有一些老生常谈的味道,但令人沮丧的是,虽然大家一而再,再而三地强调可读性,但我们的代码在可读性方面依然做得非常糟糕。由于工作的需要,我常常需要去阅读他人的代码,维护他人设计的模块。每当我看到大段大段、密密麻麻的代码,而且还没有任何的注释时常常感慨不已,深深体会到了这项工作的重要。由于分孝埋唯工的需要,我们写的代码难免需要别人去阅读和维护的。而对于许多程序员来说,他们很少去阅读和维巧培护别人的代码。正因为如此,他们很少关注代码的可读性,也对如何提高代码的可读性缺乏切身体会。有时即使为代码编写了注释,也常常是注释语言晦涩难懂形同天书,令阅读者反复斟酌依然不明其意。针对以上问题,我给大家以下建议: 1)不要编写大段的代码 如果你有阅读他人代码的经验,当你看到别人写的大段大段的代码,而且还不怎么带注释,你是怎样的感觉,是不是“嗡”地一声头大。各种各样的功能纠缠在一个方法中,各种变量来回调用,相信任何人多不会认为它是高质量的代码,但却频繁地出现在我们编写的程序了。如果现在你再回顾自己写过的代码,你会发现,稍微编写一个复杂的功能,几百行的代码就出去了。一些比较好的办法就是分段。将大段的代码经过整理,分为功能相对独立的一段又一段,并且在每段的前端编写一段注释。这样的编写,比前面那些杂乱无章的大段代码确实进步了不少,但它们在功能独立性、可复用性、可维护性方面依然不尽人意。从另一个比较专业的评价标准来说,它没有实现低耦合、高内聚。我给大家的建议是,将这些相对独立的段落另外封装成一个又一个的函数。 许多大师在自己的经典书籍中,都鼓励我们在编写代码的过程中应当养成不断重构的习惯。我们在编写代码的过程中常常要编写一些复杂的功能,起初是写在一个类的一个函数中。随着功能的逐渐展开,我们开始对复杂功能进行归纳整理,整理出了一个又一个的独立功能。这些独立功能有它与其它功能相互交流的输入输出数据。当我们分析到此处时,我们会非常自然地要将这些功能从原函数中分离出来,形成一个又一个独立的函数,供原函数调用。在编写这些函数时,我们应当仔细思考一下,为它们取一个释义名称,并为它们编写注释(后面还将详细讨论这个问题)。另一个需要思考的问题是,这些函数应当放到什么地方。这些函数可能放在原类中,也可能放到其它相应职责的类中,其遵循的原则应当是“职责驱动设计”(后面也将详细描述)。 下面是我编写的一个从XML文件中读取数据,将其生成工厂的一个类。这个类最主要的一段程序就是初始化工厂,该功能归纳起来就是三部分功能:用各种方式尝试读取文件、以DOM的方式解析XML数据流、生成工厂。而这些功能被我归纳整理后封装在一个不同的函数中,并且为其取了释义名称和编写了注释: Java代码/** * 初始化工厂。根据路径读取XML文件,将XML文件中的数据装载到工厂中 * @param path XML的路径 */publicvoid initFactory(String path){ if(findOnlyOneFileByClassPath(path)){return;} if(findResourcesByUrl(path)){return;} if(findResourcesByFile(path)){return;} this.paths = new String[]{path}; } /** * 初始化工厂。根据路径列表依次读取XML文件,将XML文件中的数据装载到工厂中 * @param paths 路径列表 */publicvoid initFactory(String[] paths){ for(int i=0; i>Java>>Code Style>>Code Templates>>Comments”中,可以简单的修改一下。 “Files”代表的是我们每新建一个文件(可能是类也可能是接口)时编写的注释,我通常设定为: Java代码/* * created on ${date} */ “Types”代表的是我们新建的接口或类前的注释,我通常设定为: Java代码/** * * @author ${user} */ 第一行为一个空行,是用于你写该类的注释。如果你采用“职责驱动设计”,这里首先应当描述的是该类的职责。如果需要,你可以写该类一些重要的方法及其用法、该类的属性及其中文含义等。 ${user}代表的是你在windows中登陆的用户名。如果这个用户名不是你的名称,你可以直接写死为你自己的名称。 其它我通常都保持为默认值。通过以上设定,你在创建类或接口的时候,系统将自动为你编写好注释,然后你可以在这个基础上进行修改,大大提高注释编写的效率。 同时,如果你在代码中新增了一个函数时,通过Alt+Shift+J快捷键,可以按照模板快速添加注释。 在编写代码时如果你编写的是一个接口或抽象类,我还建议你在@author后面增加@see注释,将该接口或抽象类的所有实现类列出来,因为阅读者在阅读的时候,寻找接口或抽象类的实现类比较困难。 Java代码/** * 抽象的单表数组查询实现类,仅用于单表查询 * @author 范钢* @see com.htxx.support.query.DefaultArrayQuery * @see com.htxx.support.query.DwrQuery */publicabstractclass ArrayQuery implements ISingleQuery { ... 2. 可维护性 软件的可维护性有几层意思,首先的意思就是能够适应软件在部署和使用中的各种情况。从这个角度上来说,它对我们的软件提出的要求就是不能将代码写死。 1)代码不能写死 我曾经见我的同事将系统要读取的一个日志文件指定在C盘的一个固定目录下,如果系统部署时没有这个目录以及这个文件就会出错。如果他将这个决定路径下的目录改为相对路径,或者通过一个属性文件可以修改,代码岂不就写活了。一般来说,我在设计中需要使用日志文件、属性文件、配置文件,通常都是以下几个方式:将文件放到与类相同的目录,使用ClassLoader.getResource()来读取;将文件放到classpath目录下,用File的相对路径来读取;使用web.xml或另一个属性文件来制定读取路径。 我也曾见另一家公司的软件要求,在部署的时候必须在C:/bea目录下,如果换成其它目录则不能正常运行。这样的设定常常为软件部署时带来许多的麻烦。如果服务器在该目录下已经没有多余空间,或者已经有其它软件,将是很挠头的事情。 2)预测可能发生的变化 除此之外,在设计的时候,如果将一些关键参数放到配置文件中,可以为软件部署和使用带来更多的灵活性。要做到这一点,要求我们在软件设计时,应当有更多的意识,考虑到软件应用中可能发生的变化。比如,有一次我在设计财务软件的时候,考虑到一些单据在制作时的前置条件,在不同企业使用的时候,可能要求不一样,有些企业可能要求严格些而有些要求松散些。考虑到这种可能的变化,我将前置条件设计为可配置的,就可能方便部署人员在实际部署中进行灵活变化。然而这样的配置,必要的注释说明是非常必要的。 软件可维护性的另一层意思就是软件的设计便于日后的变更。这一层意思与软件的可变更性是重合的。所有的软件设计理论的发展,都是从软件的可变更性这一要求逐渐展开的,它成为了软件设计理论的核心。 3. 可变更性 前面我提到了,软件的变更性是所有软件理论的核心,那么什么是软件的可变更性呢?按照现在的软件理论,客户对软件的需求时时刻刻在发生着变化。当软件设计好以后,为应对客户需求的变更而进行的代码修改,其所需要付出的代价,就是软件设计的可变更性。由于软件合理的设计,修改所付出的代价越小,则软件的可变更性越好,即代码设计的质量越高。一种非常理想的状态是,无论客户需求怎样变化,软件只需进行适当的修改就能够适应。但这之所以称之为理想状态,因为客户需求变化是有大有小的。如果客户需求变化非常大,即使再好的设计也无法应付,甚至重新开发。然而,客户需求的适当变化,一个合理的设计可以使得变更代价最小化,延续我们设计的软件的生命力。 1)通过提高代码复用提高可维护性 我曾经遇到过这样一件事,我要维护的一个系统因为应用范围的扩大,它对机关级次的计算方式需要改变一种策略。如果这个项目统一采用一段公用方法来计算机关级次,这样一个修改实在太简单了,就是修改这个公用方法即可。但是,事实却不一样,对机关级次计算的代码遍布整个项目,甚至有些还写入到了那些复杂的SQL语句中。在这样一种情况下,这样一个需求的修改无异于需要遍历这个项目代码。这样一个实例显示了一个项目代码复用的重要,然而不幸的是,代码无法很好复用的情况遍布我们所有的项目。代码复用的道理十分简单,但要具体运作起来非常复杂,它除了需要很好的代码规划,还需要持续地代码重构。 对整个系统的整体分析与合理规划可以根本地保证代码复用。系统分析师通过用例模型、领域模型、分析模型的一步一步分析,最后通过正向工程,生成系统需要设计的各种类及其各自的属性和方法。采用这种方法,功能被合理地划分到这个类中,可以很好地保证代码复用。 采用以上方法虽然好,但技术难度较高,需要有高深的系统分析师,并不是所有项目都能普遍采用的,特别是时间比较紧张的项目。通过开发人员在设计过程中的重构,也许更加实用。当某个开发人员在开发一段代码时,发现该功能与前面已经开发功能相同,或者部分相同。这时,这个开发人员可以对前面已经开发的功能进行重构,将可以通用的代码提取出来,进行相应的改造,使其具有一定的通用性,便于各个地方可以使用。 一些比较成功的项目组会指定一个专门管理通用代码的人,负责收集和整理项目组中各个成员编写的、可以通用的代码。这个负责人同时也应当具有一定的代码编写功力,因为将专用代码提升为通用代码,或者以前使用该通用代码的某个功能,由于业务变更,而对这个通用代码的变更要求,都对这个负责人提出了很高的能力要求。 虽然后一种方式非常实用,但是它有些亡羊补牢的味道,不能从整体上对项目代码进行有效规划。正因为两种方法各有利弊,因此在项目中应当配合使用。 2)利用设计模式提高可变更性 对于初学者,软件设计理论常常感觉晦涩难懂。一个快速提高软件质量的捷径就是利用设计模式。这里说的设计模式,不仅仅指经典的32个模式,是一切前人总结的,我们可以利用的、更加广泛的设计模式。 a. if...else... 这个我也不知道叫什么名字,最早是哪位大师总结的,它出现在Larman的《UML与模式应用》,也出现在出现在Mardin的《敏捷软件开发》。它是这样描述的:当你发现你必须要设计这样的代码:“if...elseif...elseif...else...”时,你应当想到你的代码应当重构一下了。我们先看看这样的代码有怎样的特点。 Java代码if(var.equals("A")){ doA(); } elseif(var.equals("B")){ doB(); } elseif(var.equals("C")){ doC(); } else{ doD(); } 这样的代码很常见,也非常平常,我们大家都写过。但正是这样平常才隐藏着我们永远没有注意的问题。问题就在于,如果某一天这个选项不再仅仅是A、B、C,而是增加了新的选项,会怎样呢?你也许会说,那没有关系,我把代码改改就行。然而事实上并非如此,在大型软件研发与维护中有一个原则,每次的变更尽量不要去修改原有的代码。如果我们重构一下,能保证不修改原有代码,仅仅增加新的代码就能应付选项的增加,这就增加了这段代码的可维护性和可变更性,提高了代码质量。那么,我们应当如何去做呢? 经过深入分析你会发现,这里存在一个对应关系,即A对应doA(),B对应doB()...如果将doA()、doB()、doC()...与原有代码解耦,问题就解决了。如何解耦呢?设计一个接口X以及它的实现A、B、C...每个类都包含一个方法doX(),并且将doA()的代码放到A.doX()中,将doB()的代码放到B.doX()中...经过以上的重构,代码还是这些代码,效果却完全不一样了。我们只需要这样写: Java代码X x = factory.getBean(var); x.doX(); 这样就可以实现以上的功能了。我们看到这里有一个工厂,放着所有的A、B、C...并且与它们的key对应起来,并且写在配置文件中。如果出现新的选项时,通过修改配置文件就可以无限制的增加下去。 这个模式虽然有效提高了代码质量,但是不能滥用,并非只要出现if...else...就需要使用。由于它使用了工厂,一定程度上增加了代码复杂度,因此仅仅在选项较多,并且增加选项的可能性很大的情况下才可以使用。另外,要使用这个模式,继承我在附件中提供的抽象类XmlBuildFactoryFacade就可以快速建立一个工厂。如果你的项目放在spring或其它可配置框架中,也可以快速建立工厂。设计一个Map静态属性并使其V为这些A、B、C...这个工厂就建立起来了。 b. 策略模式 也许你看过策略模式(strategy model)的相关资料但没有留下太多的印象。一个简单的例子可以让你快速理解它。如果一个员工系统中,员工被分为临时工和正式工并且在不同的地方相应的行为不一样。在设计它们的时候,你肯定设计一个抽象的员工类,并且设计两个继承类:临时工和正式工。这样,通过下溯类型,可以在不同的地方表现出临时工和正式工的各自行为。在另一个系统中,员工被分为了销售人员、技术人员、管理人员并且也在不同的地方相应的行为不一样。同样,我们在设计时也是设计一个抽象的员工类,并且设计数个继承类:销售人员、技术人员、管理人员。现在,我们要把这两个系统合并起来,也就是说,在新的系统中,员工既被分为临时工和正式工,又被分为了销售人员、技术人员、管理人员,这时候如何设计。如果我们还是使用以往的设计,我们将不得不设计很多继承类:销售临时工、销售正式工、技术临时工、技术正式工。。。如此的设计,在随着划分的类型,以及每种类型的选项的增多,呈笛卡尔增长。通过以上一个系统的设计,我们不得不发现,我们以往学习的关于继承的设计遇到了挑战。 解决继承出现的问题,有一个最好的办法,就是采用策略模式。在这个应用中,员工之所以要分为临时工和正式工,无非是因为它们的一些行为不一样,比如,发工资时的计算方式不同。如果我们在设计时不将员工类分为临时工类和正式工类,而仅仅只有员工类,只是在类中增加“工资发放策略”。当我们创建员工对象时,根据员工的类型,将“工资发放策略”设定为“临时工策略”或“正式工策略”,在计算工资时,只需要调用策略类中的“计算工资”方法,其行为的表现,也设计临时工类和正式工类是一样的。同样的设计可以放到销售人员策略、技术人员策略、管理人员策略中。一个通常的设计是,我们将某一个影响更大的、或者选项更少的属性设计成继承类,而将其它属性设计成策略类,就可以很好的解决以上问题。 使用策略模式,你同样把代码写活了,因为你可以无限制地增加策略。但是,使用策略模式你同样需要设计一个工厂——策略工厂。以上实例中,你需要设计一个发放工资策略工厂,并且在工厂中将“临时工”与“临时工策略”对应起来,将“正式工”与“正式工策略”对应起来。 c. 适配器模式 我的笔记本是港货,它的插头与我们常用的插座不一样,所有我出差的时候我必须带一个适配器,才能使用不同地方的插座。这是一个对适配器模式最经典的描述。当我们设计的系统要与其它系统交互,或者我们设计的模块要与其它模块交互时,这种交互可能是调用一个接口,或者交换一段数据,接受方常常因发送方对协议的变更而频繁变更。这种变更,可能是接受方来源的变更,比如原来是A系统,现在变成B系统了;也可能是接受方自身的代码变更,如原来的接口现在增加了一个参数。由于发送方的变更常常导致接受方代码的不稳定,即频繁跟着修改,为接受方的维护带来困难。 遇到这样的问题,一个有经验的程序员马上想到的就是采用适配器模式。在设计时,我方的接口按照某个协议编写,并且保持固定不变。然后,在与真正对方接口时,在前段设计一个适配器类,一旦对方协议发生变更,我可以换个适配器,将新协议转换成原协议,问题就解决了。适配器模式应当包含一个接口和它的实现类。接口应当包含一个本系统要调用的方法,而它的实现类分别是与A系统接口的适配器、与B系统接口的适配器... 我曾经在一个项目中需要与另一个系统接口,起初那个系统通过一个数据集的方式为我提供数据,我写了一个接收数据集的适配器;后来改为用一个XML数据流的形式,我又写了一个接收XML的适配器。虽然为我提供数据的方式不同,但是经过适配器转换后,输出的数据是一样的。通过在spring中的配置,我可以灵活地切换到底是使用哪个适配器。 d. 模板模式 32个经典模式中的模板模式,对开发者的代码规划能力提出了更高的要求,它要求开发者对自己开发的所有代码有一个相互联系和从中抽象的能力,从各个不同的模块和各个不同的功能中,抽象出其过程比较一致的通用流程,最终形成模板。譬如说,读取XML并形成工厂,是许多模块常常要使用的功能。它们虽然有各自的不同,但是总体流程都是一样的:读取XML文件、解析XML数据流、形成工厂。正因为有这样的特征,它们可以使用共同的模板,那么,什么是模板模式呢? 模板模式(Template Model)通常有一个抽象类。在这个抽象类中,通常有一个主函数,按照一定地顺序去调用其它函数。而其它函数往往是某这个连续过程中的各个步骤,如以上实例中的读取XML文件、解析XML数据流、形成工厂等步骤。由于这是一个抽象类,这些步骤函数可以是抽象函数。抽象类仅仅定义了整个过程的执行顺序,以及一些可以通用的步骤(如读取XML文件和解析XML数据流),而另一些比较个性的步骤,则由它的继承类自己去完成(如上例中的“形成工厂”,由于各个工厂各不一样,因此由各自的继承类自己去决定它的工厂是怎样形成的)。 各个继承类可以根据自己的需要,通过重载重新定义各个步骤函数。但是,模板模式要求不能重载主函数,因此正规的模板模式其主函数应当是final(虽然我们常常不这么写)。另外,模板模式还允许你定义的这个步骤中,有些步骤是可选步骤。对与可选步骤,我们通常称为“钩子(hood)”。它在编写时,在抽象类中并不是一个抽象函数,但却是一个什么都不写的空函数。继承类在编写时,如果需要这个步骤则重载这个函数,否则就什么也不写,进而在执行的时候也如同什么都没有执行。 通过以上对模板模式的描述可以发现,模板模式可以大大地提高我们的代码复用程度。 以上一些常用设计模式,都能使我们快速提高代码质量。还是那句话,设计模式不是什么高深的东西,恰恰相反,它是初学者快速提高的捷径。然而,如果说提高代码复用是提高代码质量的初阶,使用设计模式也只能是提高代码质量的中阶。那么,什么是高阶呢?我认为是那些分析设计理论,更具体地说,就是职责驱动设计和领域驱动设计。 3)职责驱动设计和领域驱动设计 前面我提到,当我们尝试写一些复杂功能的时候,我们把功能分解成一个个相对独立的函数。但是,应当将这些函数分配到哪个类中呢?也就是系统中的所有类都应当拥有哪些函数呢?或者说应当表现出哪些行为呢?答案就在这里:以职责为中心,根据职责分配行为。我们在分析系统时,首先是根据客户需求进行用例分析,然后根据用例绘制领域模式和分析模型,整个系统最主要的类就形成了。通过以上分析形成的类,往往和现实世界的对象是对应的。正因为如此,软件世界的这些类也具有了与现实世界的对象相对应的职责,以及在这些职责范围内的行为。 职责驱动设计(Responsibility Drive Design,RDD)是Craig Larman在他的经典著作《UML和模式应用》中提出的。职责驱动设计的核心思想,就是我们在对一个系统进行分析设计的时候,应当以职责为中心,根据职责分配行为。这种思想首先要求我们设计的所有软件世界的对象,应当与现实世界尽量保持一致,他称之为“低表示差异”。有了低表示差异,一方面提高了代码的可读性,另一方面,当业务发生变更的时候,也可以根据实际情况快速应对变更。 Craig Larman在提出职责驱动设计理论的同时,还提出了GRASP设计模式,来丰富这个理论。在GRASP设计模式中,我认为,低耦合、高内聚、信息专家模式最有用。 继Craig Larman提出的职责驱动设计数年之后,另一位大师提出了领域驱动设计。领域驱动设计(Domain Drive Design,DDD)是Eric Evans在他的同名著作《领域驱动设计》中提出的。在之前的设计理论中,领域模型是从用例模型到分析模型之间的一种中间模型,也就是从需求分析到软件开发之间的一种中间模型。这么一个中间模型,既不是需求阶段的重要产物,在开发阶段也不以它作为标准进行开发,仅仅是作为参考,甚至给人感觉有一些多余。但是,Evans在领域驱动设计中,将它放到了一个无比重要的位置。按照领域驱动设计的理论,在需求分析阶段,需求分析人员使用领域模型与客户进行沟通;在设计开发阶段,开发人员使用领域模型指导设计开发;在运行维护和二次开发阶段,维护和二次开发人员使用领域模型理解和熟悉系统,并指导他们进行维护和二次开发。总之,在整个软件开发的生命周期中,领域模型都成为了最核心的内容。 领域驱动设计继承了职责驱动设计。在领域驱动设计中强调的,依然是低表示差异,以及职责的分配。但是,如何做到低表示差异呢?如何完成职责分配呢?领域驱动设计给了我们完美的答案,那就是建立领域模型。领域驱动设计改变了我们的设计方式。在需求分析阶段,用例模型已不再是这个阶段的核心,而是建立领域模型。在开发和二次开发阶段,开发人员也不再是一埋头地猛扎进程序堆里开始编程,而是首先细致地进行领域模型分析。领域驱动设计强调持续精化,使领域模型不再是一旦完成分析就扔在一边不再理会的图纸,而是在不断理解业务的基础上不断修改和精化领域模型,进而驱动我们代码的精化。领域驱动设计强调的不再是一次软件开发过程中我们要做的工作,它看得更加长远,它强调的是一套软件在相当长一段时间内持续升级的过程中我们应当做的工作。我认为,领域驱动设计是提高代码质量的最高等级。当时,使用领域驱动设计进行软件开发是一场相当巨大的改革,它颠覆了我们过去的所有开发模式,我们必须脚踏实地地一步一步去实践和改变。 职责驱动设计 随着软件业的不断发展,随着软件需求的不断扩大,软件所管理的范围也在不断拓宽。过去一个软件仅仅管理一台电脑的一个小小的功能,而现在被扩展到了一个企业、一个行业、一个产业链。过去我们开发一套软件,只有少量的二次开发,当它使用到一定时候我们就抛弃掉重新又开发一套。现在,随着用户对软件依赖程度的不断加大,我们很难说抛弃一套软件重新开发了,更多的是在一套软件中持续改进,使这套软件的生命周期持续数年以及数个版本。正是因为软件业面临着如此巨大的压力,我们的代码质量,我们开发的软件拥有的可变更性和持续改进的能力,成为软件制胜的关键因素,令我们不能不反思。 代码质量评价的关键指标:低耦合,高内聚 耦合就是对某元素与其它元素之间的连接、感知和依赖的量度。耦合包括: 1.元素B是元素A的属性,或者元素A引用了元素B的实例(这包括元素A调用的某个方法,其参数中包含元素B)。 2.元素A调用了元素B的方法。 3.元素A直接或间接成为元素B的子类。 4.元素A是接口B的实现。 如果一个元素过于依赖其它元素,一旦它所依赖的元素不存在,或者发生变更,则该元素将不能再正常运行,或者不得不相应地进行变更。因此,耦合将大大影响代码的通用性和可变更性。 内聚,更为专业的说法叫功能内聚,是对软件系统中元素职责相关性和集中度的度量。如果元素具有高度相关的职责,除了这些职责内的任务,没有其它过多的工作,那么该元素就具有高内聚性,反之则为低内聚性。内聚就像一个专横的管理者,它只做自己职责范围内的事,而将其它与它相关的事情,分配给别人去做。 高质量的代码要求我们的代码保持低耦合、高内聚。但是,这个要求是如此的抽象与模糊,如何才能做到这些呢?软件大师们告诉我们了许多方法,其中之一就是Craig Larman的职责驱动设计。 职责驱动设计(Responsibility Drive Design,RDD)是Craig Larman在他的经典著作《UML和模式应用》中提出的。要理解职责驱动设计,我们首先要理解“低表示差异”。 低表示差异 我们开发的应用软件实际上是对现实世界的模拟,因此,软件世界与现实世界存在着必然的联系。当我们在进行需求分析的时候,需求分析员实际上是从客户那里在了解现实世界事物的规则、工作的流程。如果我们在软件分析和设计的过程中,将软件世界与现实世界紧密地联系到一起,我们的软件将更加本色地还原事物最本质的规律。这样的设计,就称之为“低表示差异”。 采用“低表示差异”进行软件设计,现实世界有什么事物,就映射为软件世界的各种对象(类);现实世界的事物拥有什么样的职责,在软件世界里的对象就拥有什么样的职责;在现实世界中的事物,因为它的职责而产生的行为,在软件世界中就反映为对象所拥有的函数。 低表示差异,使分析设计者对软件的分析和设计更加简单,思路更加清晰;使代码更加可读,阅读者更加易于理解;更重要的是
❹ 静态测试的定义
静态测试包括代码检查、静态结构分析、代码质量度量等。它可以由人工进行,充分发挥人专的逻属辑思维优势,也可以借助软件工具自动进行。代码检查包括代码走查、桌面检查、代码审查等,主要检查代码和设计的一致性,代码对标准的遵循、可读性,代码的逻辑表达的正确性,代码结构的合理性等方面;可以发现违背程序编写标准的问题,程序中不安全、不明确和模糊的部分,找出程序中不可移植部分、违背程序编程风格的问题,包括变量检查、命名和类型审查、程序逻辑审查、程序语法检查和程序结构检查等内容。
在实际使用中,代码检查比动态测试更有效率,能快速找到缺陷,发现30%~70%的逻辑设计和编码缺陷;代码检查看到的是问题本身而非征兆。但是代码检查非常耗费时间,而且代码检查需要知识和经验的积累。代码检查应在编译和动态测试之前进行,在检查前,应准备好需求描述文档、程序设计文档、程序的源代码清单、代码编码标准和代码缺陷检查表等。静态测试具有的发现缺陷早、降低返工成本、覆盖重点和发现缺陷的概率高的优点以及耗时长、不能测试依赖和技术能力要求高的缺点。