当前位置:文档之家› 如何提高代码质量

如何提高代码质量

如何提高代码质量
如何提高代码质量

我们评价高质量代码有三要素:可读性、可维护性、可变更性。我们的代码要一个都不能少地达到了这三要素的要求才能算高质量的代码。

今天这堂培训课讲什么呢?我既不讲Spring,也不讲Hibernate,更不讲Ext,我不讲任何一个具体的技术。我们抛开任何具体的技术,来谈谈如何提高代码质量。如何提高代码质量,相信不仅是在座所有人苦恼的事情,也是所有软件项目苦恼的事情。如何提高代码质量呢,我认为我们首先要理解什么是高质量的代码。

高质量代码的三要素

我们评价高质量代码有三要素:可读性、可维护性、可变更性。我们的代码要一个都不能少地达到了这三要素的要求才能算高质量的代码。

1. 可读性强

一提到可读性似乎有一些老生常谈的味道,但令人沮丧的是,虽然大家一而再,再而三地强调可读性,但我们的代码在可读性方面依然做得非常糟糕。由于工作的需要,我常常需要去阅读他人的代码,维护他人设计的模块。每当我看到大段大段、密密麻麻的代码,而且还没有任何的注释时常常感慨不已,深深体会到了这项工作的重要。由于分工的需要,我们写的代码难免需要别人去阅读和维护的。而对于许多程序员来说,他们很少去阅读和维护别人的代码。正因为如此,他们很少关注代码的可读性,也对如何提高代码的可读性缺乏切身体会。有时即使为代码编写了注释,也常常是注释语言晦涩难懂形同天书,令阅读者反复斟酌依然不明其意。针对以上问题,我给大家以下建议:

1)不要编写大段的代码

如果你有阅读他人代码的经验,当你看到别人写的大段大段的代码,而且还不怎么带注释,你是怎样的感觉,是不是“嗡”地一声头大。各种各样的功能纠缠在一个方法中,各种变量来回调用,相信任何人多不会认为它是高质量的代码,但却频繁地出现在我们编写的程序了。如果现在你再回顾自己写过的代码,你会发现,稍微编写一个复杂的功能,几百行的代码就出去了。一些比较好的办法就是分段。将大段的代码经过整理,分为功能相对独立的一段又一段,并且在每段的前端编写一段注释。这样的编写,比前面那些杂乱无章的大段代码确实进步了不少,但它们在功能独立性、可复用性、可维护性方面依然不尽人意。从另一个比较专业的评价标准来说,它没有实现低耦合、高内聚。我给大家的建议是,将这些相对独立的段落另外封装成一个又一个的函数。

许多大师在自己的经典书籍中,都鼓励我们在编写代码的过程中应当养成不断重构的习惯。我们在编写代码的过程中常常要编写一些复杂的功能,起初是写在一个类的一个函数中。随着功能的逐渐展开,我们开始对复杂功能进行归纳整理,整理出了一个又一个的独立功能。这些独立功能有它与其它功能相互交流的输入输出数据。当我们分析到此处时,我们会非常自然地要将这些功能从原函数中分离出来,形成一个又一个独立的函数,供原函数调用。在编写这些函数时,我们应当仔细思考一下,为它们取一个释义名称,并为它们编写注释(后面还将详细讨论这个问题)。另一个需要思考的问题是,这些函数应当放到什么地方。这些函数可能放在原类中,也可能放到其它相应职责的类中,其遵循的原则应当是“职责驱动设计”(后面也将详细描述)。

下面是我编写的一个从XML文件中读取数据,将其生成工厂的一个类。这个类最主要的一段程序就是初始化工厂,该功能归纳起来就是三部分功能:用各种方式尝试读取文件、以DOM的方式解析XML数据流、生成工厂。而这些功能被我归纳整理后封装在一个不同的函数中,并且为其取了释义名称和编写了注释:

1./**

2. * 初始化工厂。根据路径读取XML文件,将XML文件中的数据装载到工厂中

3. * @param path XML的路径

4. */

5.public void initFactory(String path){

6.if(findOnlyOneFileByClassPath(path)){return;}

7.if(findResourcesByUrl(path)){return;}

8.if(findResourcesByFile(path)){return;}

9.this.paths = new String[]{path};

10.}

11./**

12.* 初始化工厂。根据路径列表依次读取XML文件,将XML文件中的数据装载到工厂中

13.* @param paths 路径列表

14.*/

15.public void initFactory(String[] paths){

16.for(int i=0; i

17. initFactory(paths[i]);

18. }

19.this.paths = paths;

20.}

21./**

22.* 重新初始化工厂,初始化所需的参数,为上一次初始化工厂所用的参数。

23.*/

24.public void reloadFactory(){

25.initFactory(this.paths);

26.}

27./**

28.* 采用ClassLoader的方式试图查找一个文件,并调用readXmlStream()进行解析

29.* @param path XML文件的路径

30.* @return 是否成功

31.*/

32.protected boolean findOnlyOneFileByClassPath(String path){

33.boolean success = false;

34.try {

35. Resource resource = new ClassPathResource(path, this.getClass());

36. resource.setFilter(this.getFilter());

37. InputStream is = resource.getInputStream();

38.if(is==null){return false;}

39. readXmlStream(is);

40. success = true;

41. } catch (SAXException e) {

42. log.debug("Error when findOnlyOneFileByClassPath:"+path,e);

43. } catch (IOException e) {

44. log.debug("Error when findOnlyOneFileByClassPath:"+path,e);

45. } catch (ParserConfigurationException e) {

46. log.debug("Error when findOnlyOneFileByClassPath:"+path,e);

47. }

48.return success;

49.}

50./**

51.* 采用URL的方式试图查找一个目录中的所有XML文件,并调用readXmlStream()进行解析

52.* @param path XML文件的路径

53.* @return 是否成功

54.*/

55.protected boolean findResourcesByUrl(String path){

56.boolean success = false;

57.try {

58. ResourcePath resourcePath = new PathMatchResource(path, this.getClass());

59. resourcePath.setFilter(this.getFilter());

60. Resource[] loaders = resourcePath.getResources();

61.for(int i=0; i

62. InputStream is = loaders[i].getInputStream();

63.if(is!=null){

64. readXmlStream(is);

65. success = true;

66. }

67. }

68. } catch (SAXException e) {

69. log.debug("Error when findResourcesByUrl:"+path,e);

70. } catch (IOException e) {

71. log.debug("Error when findResourcesByUrl:"+path,e);

72. } catch (ParserConfigurationException e) {

73. log.debug("Error when findResourcesByUrl:"+path,e);

74. }

75.return success;

76.}

77./**

78.* 用File的方式试图查找文件,并调用readXmlStream()解析

79.* @param path XML文件的路径

80.* @return 是否成功

81.*/

82.protected boolean findResourcesByFile(String path){

83.boolean success = false;

84. FileResource loader = new FileResource(new File(path));

85. loader.setFilter(this.getFilter());

86.try {

87. Resource[] loaders = loader.getResources();

88.if(loaders==null){return false;}

89.for(int i=0; i

90. InputStream is = loaders[i].getInputStream();

91.if(is!=null){

92. readXmlStream(is);

93. success = true;

94. }

95. }

96.} catch (IOException e) {

97. log.debug("Error when findResourcesByFile:"+path,e);

98.} catch (SAXException e) {

99. log.debug("Error when findResourcesByFile:"+path,e);

100.} catch (ParserConfigurationException e) {

101. log.debug("Error when findResourcesByFile:"+path,e);

102.}

103.return success;

104.}

105./**

106.* 读取并解析一个XML的文件输入流,以Element的形式获取XML的根,

107.* 然后调用buildFactory(Element)构建工厂

108.* @param inputStream 文件输入流

109.* @throws SAXException

110.* @throws IOException

111.* @throws ParserConfigurationException

112.*/

113.protected void readXmlStream(InputStream inputStream) throws SAXException, IOException, ParserConfigur ationException{

114.if(inputStream==null){

115.throw new ParserConfigurationException("Cann't parse source because of InputStream is null!");

116. }

117. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

118. factory.setValidating(this.isValidating());

119. factory.setNamespaceAware(this.isNamespaceAware());

120. DocumentBuilder build = factory.newDocumentBuilder();

121. Document doc = build.parse(new InputSource(inputStream));

122. Element root = doc.getDocumentElement();

123. buildFactory(root);

124.}

125./**

126.* 用从一个XML的文件中读取的数据构建工厂

127.* @param root 从一个XML的文件中读取的数据的根

128.*/

129.protected abstract void buildFactory(Element root);

在编写代码的过程中,通常有两种不同的方式。一种是从下往上编写,也就是按照顺序,每分出去一个函数,都要将这个函数编写完,才回到主程序,继续往下编写。而一些更有经验的程序员会采用另外一种从上往下的编写方式。当他们在编写程序的时候,每个被分出去的程序,可以暂时只写一个空程序而不去具体实现功能。当主程序完成以后,再一个个实现它的所有子程序。采用这样的编写方式,可以使复杂程序有更好的规划,避免只见树木不见森林的弊病。

有多少代码就算大段代码,每个人有自己的理解。我编写代码,每当达到15~20行的时候,我就开始考虑是否需要重构代码。同理,一个类也不应当有太多的函数,当函数达到一定程度的时候就应该考虑分为多个类了;一个包也不应当有太多的类······2)释义名称与注释

我们在命名变量、函数、属性、类以及包的时候,应当仔细想想,使名称更加符合相应的功能。我们常常在说,设计一个系统时应当有一个或多个系统分析师对整个系统的包、类以及相关的函数和属性进行规划,但在通常的项目中这都非常难于做到。对它们的命名更多的还是程序员来完成。但是,在一个项目开始的时候,应当对项目的命名出台一个规范。譬如,在我的项目中规定,新增记录用new 或add开头,更新记录用edit或mod开头,删除用del开头,查询用 find或query开头。使用最乱的就是get,因此我规定,get开头的函数仅仅用于获取类属性。

注释是每个项目组都在不断强调的,可是依然有许多的代码没有任何的注释。为什么呢?因为每个项目在开发过程中往往时间都是非常紧的。在紧张的代码开发过程中,注释往往就渐渐地被忽略了。利用开发工具的代码编写模板也许可以解决这个问题。

用我们常用的MyEclipse为例,在菜单“window>>Preferences>>Java>>Code Style>>Code Templates>>Comments”中,可以简单的修改一下。

“Files”代表的是我们每新建一个文件(可能是类也可能是接口)时编写的注释,我通常设定为:

1./*

2.* created on ${date}

3.*/

“Types”代表的是我们新建的接口或类前的注释,我通常设定为:

1./**

2.*

3.* @author ${user}

4.*/

第一行为一个空行,是用于你写该类的注释。如果你采用“职责驱动设计”,这里首先应当描述的是该类的职责。如果需要,你可以写该类一些重要的方法及其用法、该类的属性及其中文含义等。

${user}代表的是你在windows中登陆的用户名。如果这个用户名不是你的名称,你可以直接写死为你自己的名称。

其它我通常都保持为默认值。通过以上设定,你在创建类或接口的时候,系统将自动为你编写好注释,然后你可以在这个基础上进行修改,大大提高注释编写的效率。

同时,如果你在代码中新增了一个函数时,通过Alt+Shift+J快捷键,可以按照模板快速添加注释。

在编写代码时如果你编写的是一个接口或抽象类,我还建议你在@author后面增加@see注释,将该接口或抽象类的所有实现类列出来,因为阅读者在阅读的时候,寻找接口或抽象类的实现类比较困难。

1./**

2.* 抽象的单表数组查询实现类,仅用于单表查询

3.* @author 范钢

4.* @see com.htxx.support.query.DefaultArrayQuery

5.* @see com.htxx.support.query.DwrQuery

6.*/

7.public abstract class ArrayQuery implements ISingleQuery {

8....

2. 可维护性

软件的可维护性有几层意思,首先的意思就是能够适应软件在部署和使用中的各种情况。从这个角度上来说,它对我们的软件提出的要求就是不能将代码写死。

1)代码不能写死

我曾经见我的同事将系统要读取的一个日志文件指定在C盘的一个固定目录下,如果系统部署时没有这个目录以及这个文件就会出错。如果他将这个决定路径下的目录改为相对路径,或者通过一个属性文件可以修改,代码岂不就写活了。一般来说,我在设计中需要使用日志文件、属性文件、配置文件,通常都是以下几个方式:将文件放到与类相同的目录,使用ClassLoader.getResource()来读取;将文件放到classpath目录下,用File的相对路径来读取;使用web.xml或另一个属性文件来制定读取路径。

我也曾见另一家公司的软件要求,在部署的时候必须在C:/bea目录下,如果换成其它目录则不能正常运行。这样的设定常常为软件部署时带来许多的麻烦。如果服务器在该目录下已经没有多余空间,或者已经有其它软件,将是很挠头的事情。

2)预测可能发生的变化

除此之外,在设计的时候,如果将一些关键参数放到配置文件中,可以为软件部署和使用带来更多的灵活性。要做到这一点,要求我们在软件设计时,应当有更多的意识,考虑到软件应用中可能发生的变化。比如,有一次我在设计财务软件的时候,考虑到一些单据在制作时的前置条件,在不同企业使用的时候,可能要求不一样,有些企业可能要求严格些而有些要求松散些。考虑到这种可能的变化,我将前置条件设计为可配置的,就可能方便部署人员在实际部署中进行灵活变化。然而这样的配置,必要的注释说明是非常必要的。

软件可维护性的另一层意思就是软件的设计便于日后的变更。这一层意思与软件的可变更性是重合的。所有的软件设计理论的发展,都是从软件的可变更性这一要求逐渐展开的,它成为了软件设计理论的核心。

3. 可变更性

前面我提到了,软件的变更性是所有软件理论的核心,那么什么是软件的可变更性呢?按照现在的软件理论,客户对软件的需求时时刻刻在发生着变化。当软件设计好以后,为应对客户需求的变更而进行的代码修改,其所需要付出的代价,就是软件设计的可变更性。由于软件合理的设计,修改所付出的代价越小,则软件的可变更性越好,即代码设计的质量越高。一种非常理想的状态是,无论客户需求怎样变化,软件只需进行适当的修改就能够适应。但这之所以称之为理想状态,因为客户需求变化是有大有小的。如果客户需求变化非常大,即使再好的设计也无法应付,甚至重新开发。然而,客户需求的适当变化,一个合理的设计可以使得变更代价最小化,延续我们设计的软件的生命力。

1)通过提高代码复用提高可维护性

我曾经遇到过这样一件事,我要维护的一个系统因为应用范围的扩大,它对机关级次的计算方式需要改变一种策略。如果这个项目统一采用一段公用方法来计算机关级次,这样一个修改实在太简单了,就是修改这个公用方法即可。但是,事实却不一样,对机关级次计算的代码遍布整个项目,甚至有些还写入到了那些复杂的SQL语句中。在这样一种情况下,这样一个需求的修改无异于需要遍历这个项目代码。这样一个实例显示了一个项目代码复用的重要,然而不幸的是,代码无法很好复用的情况遍布我们所有的项目。代码复用的道理十分简单,但要具体运作起来非常复杂,它除了需要很好的代码规划,还需要持续地代码重构。

对整个系统的整体分析与合理规划可以根本地保证代码复用。系统分析师通过用例模型、领域模型、分析模型的一步一步分析,最后通过正向工程,生成系统需要设计的各种类及其各自的属性和方法。采用这种方法,功能被合理地划分到这个类中,可以很好地保证代码复用。

采用以上方法虽然好,但技术难度较高,需要有高深的系统分析师,并不是所有项目都能普遍采用的,特别是时间比较紧张的项目。通过开发人员在设计过程中的重构,也许更加实用。当某个开发人员在开发一段代码时,发现该功能与前面已经开发功能相同,或者部分相同。这时,这个开发人员可以对前面已经开发的功能进行重构,将可以通用的代码提取出来,进行相应的改造,使其具有一定的通用性,便于各个地方可以使用。

一些比较成功的项目组会指定一个专门管理通用代码的人,负责收集和整理项目组中各个成员编写的、可以通用的代码。这个负责人同时也应当具有一定的代码编写功力,因为将专用代码提升为通用代码,或者以前使用该通用代码的某个功能,由于业务变更,而对这个通用代码的变更要求,都对这个负责人提出了很高的能力要求。

虽然后一种方式非常实用,但是它有些亡羊补牢的味道,不能从整体上对项目代码进行有效规划。正因为两种方法各有利弊,因此在项目中应当配合使用。

2)利用设计模式提高可变更性

对于初学者,软件设计理论常常感觉晦涩难懂。一个快速提高软件质量的捷径就是利用设计模式。这里说的设计模式,不仅仅指经典的32个模式,是一切前人总结的,我们可以利用的、更加广泛的设计模式。

a. if…else…

1.if(var.equals("A")){ doA(); }

2.else if(var.equals("B")){ doB(); }

3.else if(var.equals("C")){ doC(); }

4.else{ doD(); }

这样的代码很常见,也非常平常,我们大家都写过。但正是这样平常才隐藏着我们永远没有注意的问题。问题就在于,如果某一天这个选项不再仅仅是A、 B、C,而是增加了新的选项,会怎样呢?你也许会说,那没有关系,我把代码改改就行。然而事实上并非如此,在大型软件研发与维护中有一个原则,每次的变更尽量不要去修改原有的代码。如果我们重构一下,能保证不修改原有代码,仅仅增加新的代码就能应付选项的增加,这就增加了这段代码的可维护性和可变更性,提高了代码质量。那么,我们应当如何去做呢?

经过深入分析你会发现,这里存在一个对应关系,即A对应doA(),B对应doB()...如果将doA()、doB()、doC()...与原有代码解耦,问题就解决了。如何解耦呢?设计一个接口X以及它的实现A、B、C...每个类都包含一个方法doX(),并且将doA()的代码放到 A.doX()中,将doB()的代码放到B.doX()中...经过以上的重构,代码还是这些代码,效果却完全不一样了。我们只需要这样写:

1.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和模式应用》中提出的。要理解职责驱动设计,我们首先要理解“低表示差异”。

低表示差异

我们开发的应用软件实际上是对现实世界的模拟,因此,软件世界与现实世界存在着必然的联系。当我们在进行需求分析的时候,需求分析员实际上是从客户那里在了解现实世界事物的规则、工作的流程。如果我们在软件分析和设计的过程中,将软件世界与现实世界紧密地联系到一起,我们的软件将更加本色地还原事物最本质的规律。这样的设计,就称之为“低表示差异”。

采用“低表示差异”进行软件设计,现实世界有什么事物,就映射为软件世界的各种对象(类);现实世界的事物拥有什么样的职责,在软件世界里的对象就拥有什么样的职责;在现实世界中的事物,因为它的职责而产生的行为,在软件世界中就反映为对象所拥有的函数。

低表示差异,使分析设计者对软件的分析和设计更加简单,思路更加清晰;使代码更加可读,阅读者更加易于理解;更重要的是,当需求发生变更,或者业务产生扩展时,设计者只需要遵循事物本来的面貌去思考和修改软件,使软件更加易于变更和扩展。

角色、职责、协作

理解了“低表示差异”,现在我们来看看我们应当如何运用职责驱动设计进行分析和设计。首先,我们通过与客户的沟通和对业务需求的了解,从中提取出现实世界中的关键事物以及相互之间的关系。这个过程我们通常通过建立领域模型来完成。领域模型建立起来以后,通过诸如Rational Rose这样的设计软件的正向工程,生成了我们在软件系统中最初始的软件类。这些软件类,由于每个都扮演

着现实世界中的一个具体的角色,因而赋予了各自的职责。前面我已经提到,如果你的系统采用职责驱动设计的思想进行设计开发,作为一个好的习惯,你应当在每一个软件类的注释首行,清楚地描述该软件类的职责。

当我们完成了系统中软件类的制订,分配好了各自的职责,我们就应该开始根据软件需求,编写各个软件类的功能。在前面我给大家提出了一个建议,就是不要在一个函数中编写大段的代码。编写大段的代码,通常会降低代码的内聚度,因为这些代码中将包含不是该软件类应当完成的工作。作为一个有经验的开发人员,在编写一个功能时,首先应当对功能进行分解。一段稍微复杂的功能,通常都可以被分解成一个个相对独立的步骤。步骤与步骤之间存在着交互,那就是数据的输入输出。通过以上的分解,每一个步骤将形成一个独立的函数,并且使用一个可以表明这个步骤意图的释义函数名。接下来,我们应当考虑的,就是应当将这些函数交给谁。它们有可能交给原软件类,也有可能交给其它软件类,其分配的原则是什么呢?答案是否清楚,那就是职责。每个软件类代表现实世界的一个事物,或者说一个角色。在现实世界中这个任务应当由谁来完成,那么在软件世界中,这个函数就应当分配给相应的那个软件类。

通过以上步骤的分解,一个功能就分配给了多个软件类,相互协作地完成这个功能。这样的分析和设计,其代码一定是高内聚的和高可读性的。同时,当需求发生变更的时候,设计者通过对现实世界的理解,可以非常轻松地找到那个需要修改的软件类,而不会影响其它类,因而也就变得易维护、易变更和低耦合了。

说了这么多,举一个实例也许更能帮助理解。拿一个员工工资系统来说吧。当人力资源在发放一个月工资的时候,以及离职的员工肯定不能再发放工资了。在系统设计的期初,开发人员商量好,在员工信息中设定一个“离职标志”字段。编写工资发放的开发人员通过查询,将“离职标志”为false的员工查询出来,并为他们计算和发放工资。但是,随着这个系统的不断使用,编写员工管理的开发人员发现,“离职标志”字段已经不能满足客户的需求,因而将“离职标志”字段废弃,并增加了一个“离职时间”字段来管理离职的员工。然而,编写工资发放的开发人员并不知道这样的变更,依然使用着“离职标志”字段。显然,这样的结果就是,软件系统开始对离职员工发放工资了。仔细分析这个问题的原因,我们不难发现,确认员工是否离职,并不是“发放工资”软件类应当完成的工作,而应当是“员工管理”软件类应当完成的。如果将“获取非离职员工”的任务交给“员工管理”软件类,而“发放工资”软件类仅仅只是去调用,那么离职功能由“离职标志”字段改为了“离职时间”字段,其实就与“发放工资”软件类毫无关系。而作为“员工管理”的开发人员,一旦发生这样的变更,他当然知道去修改自己相应的“获取非离职员工”函数,这样就不会发生以上问题。通过这样一个实例,也许你能够理解“职责驱动设计”的精要与作用了吧。

职责分配与信息专家

通过以上对职责驱动设计的讲述,我们不难发现,职责驱动设计的精要就是职责分配。但是,在纷繁复杂的软件设计中,如何进行职责分配常常令我们迷惑。幸运的是,Larman大师清楚地认识到了这一点。在他的著作中,信息专家模式为我们提供了帮助。

信息专家模式(又称为专家模式)告诉我们,在分析设计中,应当将职责分配给软件系统中的这样一个软件类,它拥有实现这个职责所必须的信息。我们称这个软件类,叫“信息专家”。用更加简短的话说,就是将职责分配给信息专家。

为什么我们要将职责分配给信息专家呢?我们用上面的例子来说明吧。当“发放工资”软件类需要获取非离职员工时,“员工管理”软件类就是“获取非离职员工”任务的信息专家,因为它掌握着所有员工的信息。假设我们不将“获取非离职员工”的任务交给“员工管理”软件类,而是另一个软件类X,那么,为了获取员工信息,软件类X不得不访问“员工管理”软件类,从而使“发放工资”与X

耦合,X又与“员工管理”耦合。这样的设计,不如直接将“获取非离职员工”的任务交给“员工管理”软件类,使得“发放工资”仅仅与“员工管理”耦合,从而有效地降低了系统的整体耦合度。

总之,采用“职责驱动设计”的思路,为我们提高软件开发质量、可读性、可维护性,以及保持软件的持续发展,提供了一个广阔的空间。

项目成功三要素

项目成功三要素 作者:ALAN S. KOCH 项目的良好运作有赖于三大要素:人员、流程和工具。人贡献创意和智慧,流程用于弥补人的不足,工具意在提高人和流程的效率。这三大要素在项目中的地位不尽相同:人是第一要素,而工具发挥的是配角的作用,为人和流程提供支持。 要确保项目取得成功,就必须在这三大要素之间取得平衡。 要素一:人 在任何项目中,人都占据最重要的位置。没有人的参与,项目就无法进行。 创造力任何项目都离不开人的创造力。为实现某个目标或满足某个需求,人利用自己已有的知识和经验,从一个概念跃至另一概念,实现直觉上的飞跃。他们以此为跳板,探索未知世界,产生新的创意。他们会找出可以用来解决问题和应对挑战的新概念、新联系和新方法。 借助创造力,人能够从已知领域踏入未知领域,并利用在此过程中发现的新知识。机器和软件都做不到这些。人的创造力是关键。 远见远见是人具备的另一种独特的能力,它可以驱动创造力的产生。远见指的是人可以看到未来的能力,即人的想象力。机器只能看到切实存在的事物(并且往往比人还看得更清楚),而能看到未来是人所特有的能力。 任何项目都源于某人头脑中的一个远见。其倡导者会将它传达给参与项目的其他人。它指引着整个项目的运作和所有与之相关的创造力。 智慧最后,创造力和远见的结合,为智慧发挥作用提供了一个特殊的平台。智慧并不是人们想象的那么简单。人们头脑中贮存的事实只是构成了智慧的基础,但智慧远远超出了这些事实的范畴。它指的是了解这些事实的内在关系,进而将之提炼为行事原理的能力。而你可以以新的方式把这些原理应用在新的环境下。 既然人这么能干,为什么还要关注流程?为什么还要在工具上投入呢?为什么不把一切交给人来处理,并让他们来制造奇迹呢? 原因在于人并不是无所不能的。尽管人对项目的成功具有重要的作用,他们也会种下失败的种子。项目中产生的大多数问题都是由人引起的。

编写高质量代码--Web前端开发修炼之道笔记

第一章从网站重构说起 打造高质量的前端代码,提高代码的可维护性——精简、重用、有序。 第二章团队合作 精一行,通十行。 增加代码可读性——注释。 重用性需提高,分为公共组件与私有组件,代码模块化。公共组件不能轻易修改,因为影响大,所以一般只提供“读”的权限。 磨刀不误砍柴工——前期的构思很重要。构思的主要内容包括规范的制定、公共组件的设计和复杂功能的技术方案等。一般来说,前期构思占整个项目30%~60%的时间都算是正常的。 第三章高质量的HTML

CSS只是web标准的一部分,在HTML、CSS、JS三大元素中,HTML才是最重要的,结构才是重点,样式是用来修饰结构的。正确的做法是,先确定HTML,确定语义的标签,再来选用合适的CSS。 判断标签语义是否良好的简单方法:去掉样式,看网页结构是否组织良好有序,是否仍然有很好的可读性。语义良好的网页去掉样式后结构依然很清晰。 “CSS裸体日”,2006.04.05第一届,从第三届开始改为4月9日。(设立目的就是为了提醒大家用合适的HTML标签的重要性) 一个语义良好的页面,h标签应该是完整有序没有断层的,也就是说要按照h1、h2、h3、h4这样的次序排下来,不要出现类似h1、h3、h4,漏掉h2的情况。 当页面内标签无法满足设计需要时,才会适当添加div和span等五语义标签来辅助实现。 第四章高质量的CSS 组织CSS的方法:base.css+common.css+page.css,在一般情况下任何一个网页的最终表现都是由这三者共同完成的,这三者不是并列结构,而是层叠结构。

base.css一般包括cssreset和通用原子类,比如设置一些常用的清除浮动、宽度、高度等class。可以参考一些前端框架,例如YUI、bootstrap等等。 拆分模块技巧:模块与模块之间尽量不要包含相同的部分,如果有相同部分,应将它们提取出来,拆分成一个独立的模块。模块应在保证数量尽可能少的原则下,做到尽可能简单,以提高重用性。 团队开发人员多,可在classname前加前缀。 如果不确定模块的上下margin特别稳定,最好不要将它们写到模块的类里,而是使用类的组合,单独为上下margin挂用于边距的原子类(例如mt10、mb20)。模块最好不用混用margin-top和margin-bottom,统一使用margin-top或margin-bottom。 低权重原则——避免滥用子选择器 普通标签权重1,class权重10,id权重100 为了保证样式容易被覆盖,提高可维护性,CSS选择符需保证权重尽可能低。 CSS sprite的最大好处是减少HTTP请求数,减轻服务器的压力,但它却需要付出“降低开发效率”和“增大维护难度”的代价。对于流量并不大的网站来说,CSS sprite带来的好处并不明显,而它付出的代价却很大,其实并不划算。所以是否使用CSS sprite主要取决于网站流量。 编码风格:推荐一行书写,能减少文件大小。(因为调试工具多,所以忽略易读性)Hack: A标签问题:

软件工程模拟题

[模拟] 软件工程 选择题 第1题: 软件工程方法学的三要素是______。 ①方法②项目管理③过程④开发语言⑤工具 A.①②③ B.①②⑤ C.②③④ D.①③⑤ 参考答案:D 软件工程方法学包含三个要素:方法、工具和过程。方法是指完成软件开发的各项任务的技术方法;工具是指为运用方法而提供的软件工程支撑环境;过程是指为获得高质量的软件所需要完成的一系列任务的框架。 第2题: 螺旋模型的开发实施和______基本相吻合。 A.智能模型 B.快速原型模型 C.喷泉模型 D.V模型 参考答案:B 第3题: 软件设计一般分为外部设计和内部设计,它们之间的关系是______。 A.全局和局部 B.抽象和具体 C.总体和层次 D.没有关系 参考答案:A 这里所说的外部设计实际上是指概要设计,内部设计就是详细设计。概要设计的工作是:·采用某种设计方法,将一个复杂的系统按功能划分成模块;·确定每个模块的功能;·确定模块之间的调用关系;·确定模块之间的接口,即模块之间传递的信息;·评价模块结构的质量。而详细设计的工作是:·为每个模块进行详细的算法设计。用某种图形、

表格、语言等工具将每个模块处理过程的详细算法描述出来。·为模块内的数据结构进行设计。对于需求分析、概要设计确定的概念性的数据类型进行确切的定义。·对数据结构进行物理设计,即确定数据库的物理结构。物理结构主要指数据库的存储记录格式、存储记录安排和存储方法,这些都依赖于具体所使用的数据库系统。可见,这是一个全局和局部的关系,概要设计划分好模块,而详细设计定义每个模块如何工作。 第4题: 瀑布模型把软件生命周期划分为三个阶段,它们分别是:计划阶段、开发阶段和______。 A.可行性分析阶段 B.运行阶段 C.详细计划阶段 D.测试与排错阶段 参考答案:B 瀑布模型的软件生命周期分为计划阶段、开发阶段和运行阶段(即维护阶段)三个大的阶段,这三个阶段又可细分为:可行性研究、软件需求分析、系统总体设计、详细设计、编码、测试、运行维护几个小的阶段。 第5题: 瀑布模型(Waterfall Model)突出的缺点是不能适应______的变动。 A.算法 B.开发或应用平台 C.程序语言 D.用户需求 参考答案:D 瀑布模型有许多优点:可强迫开发人员采用规范的方法;严格规定了各阶段必须提交的文档;要求每个阶段结束后,都要进行严格的评审。但瀑布模型过于理想化,而且缺乏灵活性,无法在开发过程中逐渐明确用户难以确切表达或一时难以想到的需求,有时可能直到软件开发完成之后才发现与用户需求有很大距离,此时必须付出高额的代价才能纠正这一偏差。 第6题: 如果一个模块内各功能部分都使用了相同的输入数据,或产生了相同的输出数据,则称为______模块。 A.功能内聚 B.顺序内聚 C.通信内聚 D.过程内聚

编写高质量Java代码

敏捷开发中编写高质量Java代码 敏捷开发的理念已经流行了很长的时间,在敏捷开发中的开发迭代阶段中,我们可以通过五个步骤,来有效的提高整个项目的代码质量。 Java项目开发过程中,由于开发人员的经验、Java代码编写习惯,以及缺乏统一的标准和管理流程,往往导致整个项目的代码质量较差,难于维护,需要较大的测试投入和周期等问题。这些问题在一个项目组初建、需求和设计均具有不完全可预期性和完备性的全新项目中将尤为突出。 如图1所示,敏捷开发过程经历需求调研,用例分析和用例分解,进入开发迭代阶段。在每个迭代过程中,可以采用以下步骤来保证和提高整个项目的代码质量:统一编码规范、代码样式;静态代码分析(staticcodereview);单元测试;持续集成;代码评审和重构 (Revi ew&Refactor)。下文将针对每个步骤和其所使用的工具、方法进行详细描述。 图1.敏捷开发中的Java代码质量保证步骤 步骤一:统一编码规范、代码样式 规范统一的编码会增加项目代码的可读性和可维护性,但实际情况往往是项目组内的Java代码开发人员的编码风格常常各不相同,这可能是由于不同的经验习惯或者缺乏编码规范方面的学习造成的。这样一来,其他项目成员或者维护人员在阅读项目代码时就需要花费更多的时间来理解代码作者的意图,所以制定并采取统一的编码规范就显得很重要。编码规范主要应包含以下几个方面: ◆一般规则和格式规范。例如代码缩进、程序块规范、每行最大代码长度等。 ◆命名规则。例如包名、类名、变量、方法、接口、参数等命名规范 ◆文档规范。例如类文件头声明、类注释、成员变量和方法注释等规范。 ◆编程规范。例如异常、并发、多线程等方面的处理方式。 ◆其他规范。例如日志格式、属性文件格式,返回值和消息格式。

一汽大众九 大 要 素

前 言 1.一汽-大众生产现场管理系统是由哪九大部分组成? 答 2、请说明你对“一汽 - 大众生产现场管理体系”九大要素的相互关系的 九大要素的各要素环环相扣、缺一不可,都是生产管理体系中必不可少的部分,并且他们所处的位置相当于汽车的各部件在汽车中所起的作用。 目标是前进的方向;改进活动是各项工作开展的思路;目视是工作标准和内容的展示;标准化操作是使工作行为更加规范统一;工位组织是现场管理、人机工程的标准;过程控制是开展质量工作的依据;TPM 是设备管理所追求的目标,物料管理生产及维修材料管理的方法。 其中班组管理是体系的核心,因为其它各项工作都要落实到班组去开展,即班组的各项工作要遵照其它要素的要求去开展,班组管理的水平决定着其它各要素开展的深度。 作为工段长或班组长首先要认真学习各要素的工作要求和标准,并且组织班组成员来学习,指导员工按照标准的来开展各项工作,并且不断对照标准进行检查,对于存在的差距进行不断改进,并且不断循环下去。 一.KVP 2 1.什么是KVP 2 答:K-不断的;V-2.KVP 2所提的七种浪费?答:(1)生产过剩 (2)动作 (7)制作不良 二、标准化操作1.物料管理 ? 标准化工作 作 目标管理工位组织 班组管理目视管理 TPM KVP 过程控制 1、自身学习—掌握标准 2、培训并指导员工 — 如何去做 5、不断改进--提高

答:标准化操作就是跨班次制定的、统一的工作流程和工作方法。 2.标准化操作的优点是什幺? ?由班组成员负责编制“标准操作卡” ?保证各班次按相同的工作方法完成工作 ?发现并消除浪费,提高劳动生产率 ?避免缺陷,保证质量标准 ?在完成工作过程中保证工人安全 ?工作过程具有高的透明度、分工明确、目视化 ?方便新员工熟悉工作 ?是KVP2活动的基础 ?是规划工位的基础 3.在标准化操作Audit评审中,如果该工位已完成,由工业工程科授予绿色工位称号 4.标准化操作达标率怎样体现? 绿色工位数+黄色工位数 标准化操作达标率= X 100% 工位总数 5.标准化操作Audit复审频次? 答:一次/季度 6.用自己的话说明为什么要推行标准化操作? 三、班组工作: 1、什么是班组工作? 班组工作是企业在空间或专业方面有相互联系的多个员工为了独立完成工作内容和完整的工作任务而进行的紧密合作。 2、为什么开展班组工作? 开展班组工作的目的在于,在充分考虑员工目标的同时,保证企业目标的不断实现。有助提高企业竞争力,提高工作满意度,同企业保持一致。 3、设置班组园地的目的是什么? 班组园地是班组成员休息和交流的地方、是培训新员工的地方、是班组长和班组成员从事管理工作的地方。 4、对班组目视板的管理原则是什么? 答:目视內容必须与实际情况相符并体现最新状态、本着谁负责,谁维护的原则,并保持

项目管理核心三要素

项目管理三要素:时间、质量、成本工期紧,活儿只能凑合了;超支,赶紧砍内容,别弄那么多;资源有限,人手奇缺,往后拖吧。 这就是我们身边项目运作时常发生的状况。 所有的项目经理都会做预算,都会设置检查点,都知道又要无休止的协调。但真正执行起来,千变万化的现实让他们经常无所适从。 时间、质量、成本难平衡! 在纸上画一个等边三角形。在各个边上标上时间、质量、成本。我们会看到,任何一方的移动必定带动其他的变形。这个三角形中间又是什么呢?是范围管理,也就是项目范围。这个三角也就是我们常说的“项目管理三角形”。时间、成本、质量就是项目管理的三要素。有一种比喻更能说明三要素之间的关系。 小高为了取悦新认识的女朋友,精心设计了欧洲8日游,旅游花光了他多年的积蓄,旅游结束后,他再也没有财力去继续下一步的发展了。用项目管理的话说,这就是不计成本的恶果。 过了一段时间后,他又攒了一些钱,这次他不和新女朋友旅游了,他请这个姑娘看了场电影—《第一滴血》。看完后,女朋友觉得小高有暴力倾向,又分手了。这一次,小高败在不讲质量。 第三次,小高知道女孩子一般喜欢看歌舞剧,他准备请第三个女朋友去看半年后才上演的《天鹅湖》,战线一直拉着,女朋友爱上了别人——时间拖得太久了。 这个比喻形象地说明了项目管理中的难题:如何平衡三要素之间的关系? 一般来说,管理者都希望项目完成的时间要快,完成的成本要低,完成后的质量要好。可是这三个要素是彼此互斥的。能够完美做到以上三个要素的项目,少之又少。上世纪60年代初,肯尼迪总统下令要十年内把人送上月球,并安全带回来。这个庞大的计划,要快,必须赶在前苏联之前完成;要好,绝不能出现任何差错;并且在预算上有限制。 结果,在各方为这个项目大开绿灯之后,美国果真抢先把人类送上月球,并平安带了回来。当然,我们平常的项目不可能集所有人力、物力、财力等所有资源,并且得到至高无上的尚方宝剑。 因此,在一般的项目上,这三个要素,彼此之间是鱼与熊掌的关系。要兼顾的难度,会按照几何级数上升。这样一个三角难题,我们怎么去解呢?可以试着从两方面着手。 第一,先弄清楚什么是“好”,什么是“快”,什么是“便宜”。 什么是好项目?一般来说,项目的结果使企业的收入增加、支出减少、服务加强,就是好项目。 那么,什么是“快”?在项目管理上,时间是绝对的。项目经理最容易犯的错误,就是在完工日期的预测上,为了讨好上司而尽量乐观。同时,他们总用历史数据或别人的经验影响自己的预测,也使得项目工期的变化比较大。 要达到预期完工的要求,项目经理要把一个规模大、时间长的项目,分成不同的阶段完成。在每个阶段,又要根据每阶段不同的重点分别来做完工预测。工程分得越细,预测的准确性就越高。这道理很普通,但需要很周详的计划和分析。

提高代码质量的三要素

提高面试代码质量的三要素 作者:baiyuzhong分类:管理阅读:7,387 次添加评论 作者总结自己多年面试他人以及被他人面试的经验,发现应聘者可以从代码的规范性、完整性和鲁棒性三个方面提高代码的质量。 程序员在职业生涯中难免要接受编程面试。有些程序员由于平时没有养成良好的编程习惯,在面试时写出的代码质量不高,最终遗憾地与心仪的公司和职位失之交臂。因此,如何在面试时能写出高质量的代码,是很多程序员关心的问题。 代码的规范性 面试官是根据应聘者写出的代码来决定是否录用一个应聘者的。应聘者首先要把代码写得规范,才可以避免很多低级错误。如果代码写得不够规范,会影响面试官阅读代码的兴致,至少印象分会打折扣。书写、布局和命名都决定着代码的规范性。 规范的代码书写清晰。绝大部分面试都要求应聘者在白纸或者白板上书写。由于现代人已经习惯了敲键盘打字,手写变得越发不习惯,因此写出来的字潦草难辨。虽然应聘者没有必要为了面试特意去练字,但在面试过程中减慢写字速度、尽量把每个字母写清楚还是很有必要的。不用担心没有时间去写代码。通常编程面试的代码量都不会超过

50行,书写不用花多少时间,关键是在写代码之前形成清晰的思路并能把思路用编程语言清楚地书写出来。 规范的代码布局清晰。平时程序员在集成开发环境如Visual Studio里面写代码,依靠专业工具调整代码的布局,加入合理的缩进并让括号对齐成对呈现。离开这些工具,应聘者就要格外注意布局问题。当循环、判断较多逻辑较复杂时,缩进的层次可能比较多。如果布局不够清晰,缩进也不能体现体现代码的逻辑,这样的代码将会让人头晕脑胀。 规范的代码命名合理。很多初学编程的人在写代码时总是习惯用最简单的名字来命名,变量名是i、j、k,函数名是f、g、h。由于这样的名字不能告诉读者对应的变量或者函数的意义,代码一长就会变得非常晦涩难懂。强烈建议应聘者在写代码时,用完整的英文单词组合命名变量和函数,比如函数需要传入一个二叉树的根结点作为参数,则可以把该参数命名为BinaryTreeNode* pRoot。不要因为这样会多写几个字母而觉得麻烦。如果一眼能看出变量、函数的用途,应聘者就能避免自己搞混淆而犯一些低级的错误。同时合理的命名也能让面试官一眼就能读懂代码的意图,而不是让他去猜变量到底是数组中的最大值还是最小值。 代码的完整性

软件开发技术复习题

软件开发技术复习题 一、填空及简述: 1、软件、工程、软件工程及其三要素?P1-3 答:计算机系统中的程序及其文档称为软件。工程是将科学论理和知识应用于实践的科学。 软件工程是一类求解软件的工程。它应用计算机科学、数学及管理科学等原理,借鉴传统工程的原则、方法,创建软件以达到提高质量、降低成本的目的。 软件工程的三要素是指——目标、原则、活动 ①软件工程的目标可概括为“生产具有正确性、可用性以及开销合宜的产品”。 ②四条基本原则~⑴选取适宜的开发模型⑵采用合适的设计方法⑶提供高质量的工程支持⑷重视开发过程的管理 ③软件工程的活动包括~需求、设计、实现、确认和支持。 2、软件开发模型的种类、适用情况、缺点?P5-10 答:①瀑布模型~在支持结构化软件开发、控制软件开发的复杂性、促进软件开发工程化等方面起着显著作用。最为突出的缺点是该模型缺乏灵活性,无法通过开发活动澄清本来不够确切的软件需求,可能导致开发出的软件并不是用户真正需要的软件,无疑要进行返工或不得不在维护中纠正需求的偏差,为此必须付出高额的代价,为软件开发带来不必要的损失。 ②演化模型~针对事先不能完整定义需求的软件开发。但忽略风险分析。 ③螺旋模型~适合于大型软件的开发。使用时需要具有相当丰富的风险评估经验和专门知识,如果项目风险较大,又未能及时发现,势必造成重大损失。 ④喷泉模型~主要用于支持面向对象开发过程。软件刻画活动需要多次重复。 ⑤增量模型~广泛地使用开计算机工业中。需不断地进行系统的增量开发。 3、设计的分类?P43 答:软件设计可采用多种方法,如结构化设计方法、面向数据结构的设计方法、面向对象的设计方法等。 4、结构化设计方法的分类及功能?P43、P65 答:结构化设计方法分为~①总体设计。其功能是设计被建系统的模块结构,即系统实现据需要的软件模块-系统中可标识软件成分,以及这些模块之间的调用关系。 ②详细设计。这个阶段的功能是确定怎样具体地实现所需求的系统,即应该得出对目标系统的精确描述,从而在编码阶段可以将这个描述直接翻译成用某种程序设计语言书写的程序,基本上决定了最终的程序代码的质量。 5、模块及其独立性和相关内容?P56 答:模块是执行一个特殊任务或实现一个特殊的抽象数据类型的一组例程和数据结构。 模块由两部分组成~一部分是接口,列出可由其他模块或例程访问的对象,如常量、变量、数据类型、函数等;另一部分是实现模块功能的执行机制,包括私有量(只能由本模块自己使用的)及实现模块功能的过程描述或源程序代码。 6、评价软件设计的基本准则及其相关内容?P56-60 答:基本准则是“高内聚”、“低耦合”。 ⑴耦合是对不同模块之间相互依赖程度的度量。 紧密耦合是指两个模块之间存在着很强的依赖关系;松散耦合是指两个模块之间存在一些依赖关系,但它们之间的连接比较弱;无耦合是指模块之间根本没有任何连接。 耦合的强度依赖于以下几个因素~①一个模块对另一个模块的引用②一个模块向另一个模块传递的数据量③一个模块施加到另一个模块的控制的数量④模块之间接口的复杂程度 耦合的类型(从强到弱)~①内容耦合②公共耦合③控制耦合④标记耦合⑤数据耦合 ⑵内聚度量的是一个模块内部各成分之间相互关联的强度。一个模块内聚程度越高,该模块的内部各成分之间以及同模块所完成的功能之间的关联也就越强。

敏捷开发中编写高质量Java代码+

敏捷开发中编写高质量Java代码收藏 敏捷开发的理念已经流行了很长的时间,在敏捷开发中的开发迭代阶段中,我们可以通过五个步骤,来有效的提高整个项目的代码质量。 Java项目开发过程中,由于开发人员的经验、Java代码编写习惯,以及缺乏统一的标准和管理流程,往往导致整个项目的代码质量较差,难于维护,需要较大的测试投入和周期等问题。这些问题在一个项目组初建、需求和设计均具有不完全可预期性和完备性的全新项目中将尤为突出。 如图1所示,敏捷开发过程经历需求调研,用例分析和用例分解,进入开发迭代阶段。在每个迭代过程中,可以采用以下步骤来保证和提高整个项目的代码质量:统一编码规范、代码样式;静态代码分析(staticcodereview);单元测试;持续集成;代码评审和重构(Review&Refact or)。下文将针对每个步骤和其所使用的工具、方法进行详细描述。 图1.敏捷开发中的Java代码质量保证步骤

步骤一:统一编码规范、代码样式 规范统一的编码会增加项目代码的可读性和可维护性,但实际情况往往是项目组内的Java代码开发人员的编码风格常常各不相同,这可能是由于不同的经验习惯或者缺乏编码规范方面的学习造成的。这样一来,其他项目成员或者维护人员在阅读项目代码时就需要花费更多的时间来理解代码作者的意图,所以制定并采取统一的编码规范就显得很重要。编码规范主要应包含以下几个方面: ◆一般规则和格式规范。例如代码缩进、程序块规范、每行最大代码长度等。 ◆命名规则。例如包名、类名、变量、方法、接口、参数等命名规范 ◆文档规范。例如类文件头声明、类注释、成员变量和方法注释等规范。 ◆编程规范。例如异常、并发、多线程等方面的处理方式。 ◆其他规范。例如日志格式、属性文件格式,返回值和消息格式。 项目的编码规范可以参考已有的一些Java编程规范书籍和其他相关资料并结合项目的本身来制定,可供参考的书籍有《Java编程风格》(英文书名为:TheElementsofJavaStyle)。编码规范要形成文档,而且要简洁明了,并组织项目成员一起学习,确保所有成员正确理解所有条目。 一旦编码规范确定,就可以利用Eclipse自身提供的功能来控制代码样式和格式。具体做法是,点击Eclipse的Windows->Preference菜单项,在打开的Preferences对话框的左侧栏中找到Java节点下的子项CodeStyle(如图2),该项和它的子项允许您对Java代码的样式进行控制。

新闻稿效果的三要素

新闻稿趋势: a 百度屏蔽主词的首页排名 b 百度针对医院夸大宣传等广告词不给予百度首页排名(好、最好、最权威、治愈率100%等等) c 百度针对赤裸裸广告性质形式文章给予打压 d 百度针对大量重复性软文给予打压 针对新闻稿现在趋势我们从关键词定位文章写法媒体部署三大块入手,把新闻源的效果做到最大化 关键词定位 首先我们要明白新闻源作用,新闻源主要是用来做到诊的而不是做品牌推广和医院曝光的,做品牌推广和医院曝光的可以在新浪,搜狐,39健康网,求医问药等权威的大型门户站做一些主词通用词,这些词的流量特别高,曝光也高。虽然流量高,但是转换率不一定就高。所以新闻是用来做到诊是最佳的,那我们新闻稿该如何定位关键词啦,我们通过大数据分析,并且多家成功案例作参考,发现就现价段新闻稿应该做精准的长尾词到诊词而不是主词和通用词。至于为什么做这些词,有哪些好处啦,原因有如下几点: (1)长尾词转换率高于主词转换率(大家公认的) (2)长尾词容易垄断首页,主词不容易产生垄断(无论是百度、360、搜狗等都一样),所以虽然单个长尾词搜索量有限,但是只要有流量那么这个流量就非常容易产生到诊。而并不是高流量就有高到诊低流量就没有到诊了。 (3)长尾词很容易产生匹配,通常1000个长尾关键词可以匹配出3000个相关关键词的百度首页排名 最后说一点,我们所发的长尾精准关键词不是凭空想象出来的,必须是通过商务通导出真正有搜索量的关键词,根据这些词来着。

文章写法 百度现在对软文质量要求是越来越高了,通过百度最近一段时间的几次调整,我们发现百度是对那种原创度高,没有任何广告性质和虚假信息的并且是公益性的文章做喜好了,像这类文章百度给的效果都不低,而且首页存活期也比一般的文章长,那么我们怎么提高文章的原创度,靠传统方法,文章的每一段落都原创一下是行不通,因为太耗时间了,针对这种情况,根据JS调用的信息百度抓取不到的原理,我们研究一种”文字+JS调用”相结合一种新方法。 准备工作: 事先把你们医院的一些信息疗法图片商务通和活动介绍等信息做成HTML代码形式的模板,然后JS封装一下(就是JS调用HTML页面,你们技术应该懂得,如果有不明白的私聊我)。前期我们可以把这些模板做几套出来,轮流使用,这样可以避免页面的重复问题,用户的体验度也高了,建议这些JS模板都做成 UTF-8和GB2312两种编码的,因为我们的媒体编码就是UTF-8和GB2312两种编码的。到时候按照媒体不同选择JS。 开始工作: 文章的首段和第二段写一些原创性高的公益性文章,原创不要太高80-120就差不多了,从第三段起直接放你要调用的JS模板就可以了(文章的第一二段要和JS模板里面的内容自然融入)。 因为你们医院的所有重复信息都写在JS里面,百度蜘蛛爬寻时,只抓取你文章的首段和第二段,根本抓取不到JS里面的信息,所以百度认为你们的文章质量自然就高了,自然给这篇文章的排名效果也不低。 媒体部署 我们合众康桥只做有效的媒体,只要是市场好媒体我们都采购,我们后台每

(完整版)一汽大众九大要素。。

前 言 1.一汽-大众生产现场管理系统是由哪九大部分组成? 答 2、请说明你对“一汽 - 大众生产现场管理体系”九大要素的相互关系的 看法。做为工段长或班组长你在推行九大要素中应该怎样去做? ? 九大要素的各要素环环相扣、缺一不可,都是生产管理体系中必不可少的部分,并且他们所处的位置相当于汽车的各部件在汽车中所起的作用。 ? 目标是前进的方向;改进活动是各项工作开展的思路;目视是工作标准和内容的展示;标准化操作是使工作行为更加规范统一;工位组织是现场管理、人机工程的标准;过程控制是开展质量工作的依据;TPM 是设备管理所追求的目标,物料管理生产及维修材料管理的方法。 ? 其中班组管理是体系的核心,因为其它各项工作都要落实到班组去开展,即班组的各项工作要遵照其它要素的要求去开展,班组管理的水平决定着其它各要素开展的深度。 作为工段长或班组长首先要认真学习各要素的工作要求和标准,并且组织班组成员来学习,指导员工按照标准的来开展各项工作,并且不断对照标准进行检 物料管理 ? 标准化工作作 目标管理工位组织 班组管理目视管理 TPM KVP 过程控制

查,对于存在的差距进行不断改进,并且不断循环下去。 1、自身学习—掌握标准 一.KVP2 1.什么是KVP2 答:K-不断的;V-改进;P-过程; 2-代表以平方的速度跳跃式的 2.KVP2所提的七种浪费? 答:(1)生产过剩 (2)等待 (3)搬运 (4)加工本身 (5)库存提高 (6)动作 (7)制作不良 二、标准化操作 1.什么是标准化操作? 答:标准化操作就是跨班次制定的、统一的工作流程和工作方法。 2.标准化操作的优点是什幺? ?由班组成员负责编制“标准操作卡” ?保证各班次按相同的工作方法完成工作

如何提高代码质量

我们评价高质量代码有三要素:可读性、可维护性、可变更性。我们的代码要一个都不能少地达到了这三要素的要求才能算高质量的代码。 今天这堂培训课讲什么呢?我既不讲Spring,也不讲Hibernate,更不讲Ext,我不讲任何一个具体的技术。我们抛开任何具体的技术,来谈谈如何提高代码质量。如何提高代码质量,相信不仅是在座所有人苦恼的事情,也是所有软件项目苦恼的事情。如何提高代码质量呢,我认为我们首先要理解什么是高质量的代码。 高质量代码的三要素 我们评价高质量代码有三要素:可读性、可维护性、可变更性。我们的代码要一个都不能少地达到了这三要素的要求才能算高质量的代码。 1. 可读性强 一提到可读性似乎有一些老生常谈的味道,但令人沮丧的是,虽然大家一而再,再而三地强调可读性,但我们的代码在可读性方面依然做得非常糟糕。由于工作的需要,我常常需要去阅读他人的代码,维护他人设计的模块。每当我看到大段大段、密密麻麻的代码,而且还没有任何的注释时常常感慨不已,深深体会到了这项工作的重要。由于分工的需要,我们写的代码难免需要别人去阅读和维护的。而对于许多程序员来说,他们很少去阅读和维护别人的代码。正因为如此,他们很少关注代码的可读性,也对如何提高代码的可读性缺乏切身体会。有时即使为代码编写了注释,也常常是注释语言晦涩难懂形同天书,令阅读者反复斟酌依然不明其意。针对以上问题,我给大家以下建议: 1)不要编写大段的代码 如果你有阅读他人代码的经验,当你看到别人写的大段大段的代码,而且还不怎么带注释,你是怎样的感觉,是不是“嗡”地一声头大。各种各样的功能纠缠在一个方法中,各种变量来回调用,相信任何人多不会认为它是高质量的代码,但却频繁地出现在我们编写的程序了。如果现在你再回顾自己写过的代码,你会发现,稍微编写一个复杂的功能,几百行的代码就出去了。一些比较好的办法就是分段。将大段的代码经过整理,分为功能相对独立的一段又一段,并且在每段的前端编写一段注释。这样的编写,比前面那些杂乱无章的大段代码确实进步了不少,但它们在功能独立性、可复用性、可维护性方面依然不尽人意。从另一个比较专业的评价标准来说,它没有实现低耦合、高内聚。我给大家的建议是,将这些相对独立的段落另外封装成一个又一个的函数。

软件代码质量控制

也许你是一位项目经理,也许你是一位项目骨干成员,或者开发小组长。在我发表“如何提高代码质量”的这一系统文章后,有许多网友都向我抱怨,说他无法把握整个项目组成员的代码质量。我想,这也是所有项目组普遍存在的问题吧,它通常表现为以下几个问题: 软件项目普遍存在的问题 1)新手。任何项目组成员都不可避免地出现新手,他们往往是刚刚从大学毕业的学生。这些新手由于软件开发时间太短,往往技术不成熟,没有形成良好的开发习惯,所以编写代码质量较差,问题很多。他们常常成为项目组的“鸡肋”,用多了项目质量无法得到保证,不用则又人手不够。 2)人员变动。一个维护时间稍长一点儿的软件项目,人员变动是在所难免的。老员工被调动到其它项目去了,由新员工来接替他们的工作。在我的项目组中,人员调动达到了90%,唯一没有调走的就是我自己。新员工在接替老员工进行代码维护,甚至继续进行新的开发的时,由于对原有代码以及设计思路理解的偏差,也会出现大量的低劣代码。 3)不规范的代码编写。即使除去以上两个问题的影响,项目组成员编写的代码同样会出现问题。在项目开发之初,我们往往会制定一个代码编写的规范,但在项目开发过程中,许多成员往往会忽视这些代码规范而进行随意的编写。随意地代码编写会降低代码的可读性、可维护性和易变更性。那么,我们应当采用什么样的管理措施,保证代码的规范,提高代码的质量呢? 以上问题,也是我在项目开发中不断摸索和思考的问题,而一些有经验的项目经理给出了他们的解决之道,那就是“代码复查”。 什么是代码复查 代码复查(Code Review),又叫“代码审查”,其基本思想就是,在开发人员编写完自己的代码后,由其他人来复查他写的代码,从而有效地发现代码中存在的缺陷。代码复查的一个基本理论就是,当我们越早发现代码存在的缺陷,我们解决缺陷的代价就越低。代码复查往往分成以下一个方面进行审查:1)代码风格。在项目开发之初,我们往往会制定一个代码编写的规范,实际上,这个代码规范就包含了整个项目组的代码风格。由于软件开发人员的设计习惯不同,如果不统一代码风格,一个项目中的代码将五花八门,如变量和常量的命名、接口与实现类的注释、何时回车、怎样缩进等等。一个五花八门的设计风格,必将为日后的维护与改进带来困难。我们通过代码复查,一方面督促开发人员按照规范编写代码,另一方面也使开发人员自身形成良好的编程习惯。代码

论文分类号 单 位 代 码 10183 - 吉林大学图书馆

论文分类号单位代码 10183 密级研究生学号 990202 吉林大学 硕士学位论文形态和色彩的即时设计与产品造型的创意和表现 Color and Form Design, Design Just In Time and Plastic Design in Products Design 作者姓名:黎晓 专业:设计艺术学 导师姓名兰凤崇教授 及职称 论文起止年月:年月至年月

提要 工业设计的理念是个性设计和整体协调。这是一个思路问题,用什么样的思维和理念去塑造一个形象、表现一个形象并且这个形象是具体的,面向大众的是当今工业设计业内人士都在普遍思考的问题。 本文通过分析现代工业设计中产品设计的主要趋势和特点提出了以外部形态和色彩为着眼点的“即时设计”的设计思想。针对我国的工业设计现状,强调了在产品设计过程中“形态和色彩的即时设计”具有重要的意义。旨在通过阐述“形态和色彩的即时设计”在现代工业设计中的作用来使更多人认识到形式设计的现时意义并对传统的“形式服从功能”说应给予重新理解和定义,这样才会有助于用符合时代要求的设计思想指导设计活动,从而推动我国的工业设计更快发展。 工业设计尤其是产品造型设计的成功关键绝大多数由创意决定, 而且创意也是设计的灵魂。创意从某种意义上来说既基于时间又超越时间。在产品由大批量生产转向小批量生产和精细化制造的时期,产品的最初创意起到了导向的作用。本文提出了“形态和色彩的即时设计”是要强调形式设计的现时重要性,并且通过阐述“形态和色彩的即时设计”对于产品造型创意和表现的意义对此做了进一步论证。形态和色彩的即时设计所要表达两方面意思:一.产品造型创意“以小见大”,用细节(形,色)平衡全局(产品的亲和力及产品的附加值);二.把握时机,以时代特征为参照,达到人与物更加和谐的沟通。

如何提高代码质量

一、提高编码质量的重要性: 代码是写给别人看,给别人用的。 一要考虑代码移交给别人维护;二是要考虑代码的各模块给别人复用。 二、执行的质量标准: 可读性、可维护性、易用性、可扩展性、可复用性、鲁棒性 1、可读性、可维护性 初级要求:别人拿到你的代码,没有阅读障碍,不需要向你请教也能看懂。 高级要求:别人可以花很少的时间看懂。 1)注释 a、文件注释:这个文件是干嘛的 b、模块注释:这个模块完成什么功能。对于嵌入式中资源的驱动,尽量描绘出 资源的信息。譬如flash驱动,应该描述出基地址、长度、扇区数、扇区的 基地址等。 c、逻辑注释:这个复杂的逻辑是如何实现的 d、函数注释:这个函数完成什么功能,该怎么用 e、功能块注释:这个函数内的这段话,要实现什么功能 f、变量注释:这个变量的作用 g、其它注释:宏定义、结构体、枚举、联合体等 2)版式 致力于让阅读更轻松 a、适量的使用空行,隔开不同的功能块 b、长行拆分 c、对齐 d、一行定义一个变量 e、尽量使用括号、花括号 f、变量的初始化 g、函数不要太长,长了之后考虑是否可以拆分 3)命名规则(风格) 从名字间获取最大量的信息,降低阅读障碍,提高阅读速度。 a、命名风格统一 b、顾名思义,名字应能准确反映出意思 c、命名要能明确区分出不同的类别:函数、宏、结构体、常量、全局变量、静 态变量、常量。 d、匈牙利命名法:强调变量的类型。 e、文件命名风格也要统一 4)模块化、层次清楚 阅读时,首先能总览全局,知道都有什么;对任何关注的局部,可以直接展开。 a、希望它是一棵树,不是一张蜘蛛网。 低耦合。 b、一棵面向对象的树

高质量代码三要素

高质量代码的三要素 我们评价高质量代码有三要素:可读性、可维护性、可变更性。我们的代码要一个都不能少地达到了这三要素的要求才能算高质量的代码。 1.可读性强 一提到可读性似乎有一些老生常谈的味道,但令人沮丧的是,虽然大家一而再,再而三地强调可读性,但我们的代码在可读性方面依然做得比较糟糕。每当我看到大段大段、密密麻麻的代码,而且还没有任何的注释时常常感慨不已,深深体会到了这项工作的重要。由于分工的需要,我们写的代码难免需要别人去阅读和维护的。而对于许多程序员来说,他们很少去阅读和维护别人的代码。正因为如此,他们很少关注代码的可读性,也对如何提高代码的可读性缺乏切身体会。有时即使为代码编写了注释,也常常是注释语言晦涩难懂形同天书,令阅读者反复斟酌依然不明其意。针对以上问题,我给大家以下建议: 1)不要编写大段的代码 如果你有阅读他人代码的经验,当你看到别人写的大段大段的代码,而且还不怎么带注释,你是怎样的感觉,是不是“嗡”地一声头大。各种各样的功能纠缠在一个方法中,各种变量来回调用,相信任何人都不会认为它是高质量的代码,但却频繁地出现在我们编写的程序了。如果现在你再回顾自己写过的代码,你会发现,稍微编写一个复杂的功能,几百行的代码就出去了。一些比较好的办法就是分段。将大段的代码经过整理,分为功能相对独立的一段又一段,并且在每段的前端编写一段注释。这样的编写,比前面那些杂乱无章的大段代码确实进步了不少,但它们在功能独立性、可复用性、可维护性方面依然不尽人意。从另一个比较专业的评价标准来说,它没有实现低耦合、高内聚。我给大家的建议是,将这些相对独立的段落另外封装成一个又一个的函数。 许多大师在自己的经典书籍中,都鼓励我们在编写代码的过程中应当养成不断重构的习惯。我们在编写代码的过程中常常要编写一些复杂的功能,起初是写在一个类的一个函数中。随着功能的逐渐展开,我们开始对复杂功能进行归纳整理,整理出了一个又一个的独立功能。这些独立功能有它与其它功能相互交流的输入输出数据。当我们分析到此处时,我们会非常自然地要将这些功能从原函数中分离出来,形成一个又一个独立的函数,供原函数调用。在编写这些函数时,我们应当仔细思考一下,为它们取一个释义名称,并为它们编写注释(后面还将详细讨论这个问题)。另一个需要思考的问题是,这些函数应当放到什么地方。这些函数可能放在原类中,也可能放到其它相应职责的类中,其遵循的原则应当是“职责驱动设计”(后面也将详细描述)。 在编写代码的过程中,通常有两种不同的方式。一种是从下往上编写,也就是按照顺序,每分出去一个函数,都要将这个函数编写完,才回到主程序,继

如何提高代码质量(管理篇):代码复查

如何提高代码质量(管理篇):代码复查 也许你是一位项目经理,也许你是一位项目骨干成员,或者开发小组长。在我发表“如何提高代码质量”的这一系统文章后,有许多网友都向我抱怨,说他无法把握整个项目组成员的代码质量。我想,这也是所有项目组普遍存在的问题吧,它通常表现为以下几个问题: 软件项目普遍存在的问题 1)新手。任何项目组成员都不可避免地出现新手,他们往往是刚刚从大学毕业的学生。这些新手由于软件开发时间太短,往往技术不成熟,没有形成良好的开发习惯,所以编写代码质量较差,问题很多。他们常常成为项目组的“鸡肋”,用多了项目质量无法得到保证,不用则又人手不够。 2)人员变动。一个维护时间稍长一点儿的软件项目,人员变动是在所难免的。老员工被调动到其它项目去了,由新员工来接替他们的工作。在我的项目组中,人员调动达到了90%,唯一没有调走的就是我自己。新员工在接替老员工进行代码维护,甚至继续进行新的开发的时,由于对原有代码以及设计思路理解的偏差,也会出现大量的低劣代码。 3)不规范的代码编写。即使除去以上两个问题的影响,项目组成员编写的代码同样会出现问题。在项目开发之初,我们往往会制定一个代码编写的规范,但在项目开发过程中,许多成员往往会忽视这些代码规范而进行随意的编写。随意地代码编写会降低代码的可读性、可维护性和易变更性。那么,我们应当采用什么样的管理措施,保证代码的规范,提高代码的质量呢? 以上问题,也是我在项目开发中不断摸索和思考的问题,而一些有经验的项目经理给出了他们的解决之道,那就是“代码复查”。 什么是代码复查 代码复查(Code Review),又叫“代码审查”,其基本思想就是,在开发人员编写完自己的代码后,由其他人来复查他写的代码,从而有效地发现代码中存在的缺陷。代码复查的一个基本理论就是,当我们越早发现代码存在的缺陷,我们解决缺陷的代价就越低。代码复查往往分成以下一个方面进行审查: 1)代码风格。在项目开发之初,我们往往会制定一个代码编写的规范,实际上,这个代码规范就包含了整个项目组的代码风格。由于软件开发人员的设计习惯不同,如果不统一代码风格,一个项目中的代码将五花八门,如变量和常量的命名、接口与实现类的注释、何时回车、怎样缩进等等。一个五花八门的设计风格,必将为日后的维护与改进带来困难。我们通过代码复查,一方面督促开发人员按照规范编写代码,另一方面也使开发人员自身形成良好的编程习惯。代码风格的审查,由于内容比较单一,我们常常可以通过一些代码复查的工具来自动完成,提高复查的效率。 2)重大缺陷。在一些关于代码复查的文章中,列出了一个常常的单子,描述了代码复查应当着重注意的重大缺陷,它们包括:存在SQL注入、易受跨站点脚本攻击、缓存区溢出、托管代码等等。项目组可以不断积累重大缺陷的审查项目,并在每次审查中逐一检查。重大缺陷审查是一个繁琐而细致的工作,如果能编写或使用一些审查软件,可以大大提高我们的审查效率。 3)设计逻辑与思路的审查。我认为,这部分的审查是代码复查中最核心、最有价值的部分。代码风格与重大缺陷的审查,虽然重要但简单而机械,可以通过软件自动检查;而设计逻辑与思路的审查,却是复杂而

软件工程复习重点答案

软件工程复习重点 一、选择题 1、软件工程三要素是指( B )P8 A、技术、方法和工具 B、方法、工具和过程 C、方法、对象和类 D、过程、模型、方法 2、瀑布模型本质上是一种( A )。P23 A、线性顺序模型 B、顺序迭代模型 C、线性迭代模型 D、及早见产品模型 3、结构化设计是一种应用最广泛的系统设计方法,是以( B )为基础,自顶向下,求精和模块化的过 程。P79 A、数据流 B、数据流图 C、数据库 D、数据结构 4、概要设计的任务是设计系统的( B物理模型)P70 A、逻辑模型 B、物理模型 C、概念模型 D、程序流程图 5、描述软件结构的工具有( A模块结构图) A、模块结构图 B、PAD图 C、数据流程图 D、程序 6、进行需求分析可以使用多种工具,但( C )是不适用的。 A、数据流程图 B、判定表 C、PAD图(详细设计) D、数据字典 7、可行性研究要进行的需求分析和设计应该是( C )。 A、详细的 B、全面的 C、简化的、压缩的 D、彻底的 8、软件生命周期由( C )三个时期组成。 A、概要设计、详细设计和系统实现 B、可行性分析、系统设计和编码 C、定义、开发和运行维护 D、分析、设计和测试 9、以下( D )不是模块。对象是一个实体 A、过程 B、程序 C、函数 D、对象 10、程序流程图、N-S图和PAD图是( B )使用的算法表达工具。 A、设计阶段的概要设计 B、设计阶段的详细设计 C、编码阶段 D、测试阶段 11、一个模块直接控制(调用)的下层模块的数目称为模块的( B扇出)P78 A、扇入数 B、扇出数 C、宽度 D、作用域 12、下列工具哪一个是需求分析阶段常用工具?( D ) A、PAD B、PFD C、N-S D、DFD数据流程图 需求分析常用的是数据流程图和数据字典 13、为了提高测试的效率,应该( D) A、随机地选取测试数据 B、取一切可能的输入数据作为测试数据库 C、在完成编码后制定软件的测试计划 D、选择发现错误可能性大的数据作为测试数据 14、成功的测试是指( B发现程序的错误) A、运行测试实例后未发现错误项 B、发现程序的错误 C、证明程序正确 D、改正程序的错误 15、软件工程中只根据程序的功能说明而不关心程序内部的逻辑结构的测试方法,称为( C黑盒测试)

相关主题
文本预览
相关文档 最新文档