《软件工程实践6编程.ppt》由会员分享,可在线阅读,更多相关《软件工程实践6编程.ppt(68页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、北京理工大学软件工程实践汤铭端中国航天科工集团公司204所第五讲软件实现内容和目的n编程语言的选择 n编程风格n程序效率n编码要求n静态分析n代码审查n软件调试编程n编程是设计的自然结果n编程语言的特性和编程风格会深刻地影响软件的重量和可维护性n软件实现是一个不断变换的过程:设计源程序目标代码机器码编程语言的选择n应用领域n算法及运算的复杂性n软件运行的环境n性能n数据结构的复杂性n软件开发组成员对该语言的熟悉程度编程风格n程序必须是可以理解的n程序的风格应该强调简单和清晰n影响程序风格的因素有:n源程序内部文档化n数据说明的方法n语句的结构nI/O的方法源程序文档化n选择好标识符(变量和标号
2、)的名字n挑选有意义的标识符名字n安排注解n序言式注解(头文件)n功能注解n使程序的结构一目了然n缩进数据说明n数据说明的次序应该规范化n多个变量说明时最好按字典数顺序排列n对复杂结构用注解说明语句结构n每个语句应该简单直接,不应该为提高效率而把语句复杂化n使程序简单易懂n避免采用复杂的条件语句n不要用“否定”条件的条件语句n避免多重的循环嵌套或条件嵌套n用括号使逻辑表达式或算术表达式更为清晰n用空格及有意义的符号使语句内容清晰明确n反问自己“如果这程序不是我编的,我能看懂吗?”输入/输出n对批处理I/On符合逻辑地组织输入nI/O出错检查n好的I/O出错恢复功能n清晰的输出报告格式n对交互式
3、I/On简单而有提示的输入方式n完备的出错处理及出错恢复n人机对话输出nI/O格式的一致性n原则:n检查所有输入数据的合法性n检查输入项的各种重要组合是否合理n输入格式要简单n最好采用数据结尾指示符,而不应要求用户规定“输入项目的数量”n交互式I/O要求用户输入时,标明交互输入可选择的种类和范围n输出时保持格式的一致性n设计和标明所有的输出Wasserman交互系统设计原则原则n把计算机的内部特性掩盖起来不让用户看到n使程序“穿上防弹衣”,保证程序不被用户破坏n如果用户的请求会产生重大的后果,就要提醒用户n在使用此程序时提供联机的帮助条件n按照用户的水平设计输入要求n按照输出设备的速度设计输出
4、信息n区别对待不同类型的用户n保持一致的响应时间n应尽量减少用户处理出错的工作量效率n要求有效地利用临界资源是自然的nCPU周期和内存单元常被看作临界资源n有关效率的三个格言:n效率是一种性能需求。软件的效率应根据需要,而不是尽可能地高!n好的设计必然提高效率。n程序的简单性与程序的效率往往是一致的。n总之不要去牺牲程序的清晰性、可读性或正确性去追求效率的非本质的提高源程序的效率n源程序的效率与算法效率直接相关n编程风格会影响运行速度及所需内存的大小n编译器的“优化”特性是提高效率的一种手段n原则:n在具体编程前应简化算术表达式及逻辑表达式n细心地分析多层嵌套循环以确定能否把一些语句或表达式移
5、到循环之外n尽量避免采用多维数组n尽量避免采用指针及复杂的表n采用“快”的算术运算n不要把不同的数据类型混在一起n只要可能就采用整型数的算术运算和布尔表达式内存效率n大机器领域内存几乎无限制,虚存使“内存效率”不等同于“占用最小的内存”n微机领域内存的限制仍是很现实的问题n采用汇编语言可以节省内存n提高运行效率的技术往往可以同时节省内存n使程序简单是提高内存效率的关键输入输出效率n提高I/O效率的指导原则:n全部I/O应有缓冲以避免过于频繁的信息交换n对外存应该选用最简单的可接收的存取方式n与外存联系的I/O操作应成块地传送数据n与终端及行式打印机联系的I/O操作应考虑设备的特性,以改进质量与
6、速度n如果“超高效率”的I/O无法被人们理解,则是毫无意义的Kernighan和Plauger给出的好的程序设计风格的规则n写得清晰而不是太灵巧n简单而直接地说明你的用意n使用库功能n避免使用临时变量n写清晰不要为了“效率”而牺牲清晰n让机器干苦活n用调用一个公共的例程去代替重复的表示n选用不易混淆的变量名n避免使用不必要的转移Kernighan和Plauger给出的好的程序设计风格的规则n不使用条件转移代替一个逻辑表达式n假如一个逻辑表达式难以理解,则试着对其进行变换n使用数组,避免重复的控制序列n选用使程序简单的数据表示法n先用一个容易理解的伪语言写程序,然后再翻译成你所用的语言使用IFE
7、LSEIFELSEIFELSEENDIF实施多路选择n模块化,使用子例程Kernighan和Plauger给出的好的程序设计风格的规则n确保注释与代码一致n不要用注释去精确地重复代码使每一个注释有价值n不要注释或修补坏代码重写n使用有意义的变量名n使用有意义的语句标号n程序格式应有助于读者理解程序n为你的数据设计提供文档n仅使用GOTO去实施一个基本的结构Kernighan和Plauger给出的好的程序设计风格的规则n假如你能保持程序的可读性,则完全不必使用GOTOn以小片段的方式写和测试一个大程序n对已定义的递归数据结构使用递归过程n检测输入的合理性和合法性n确保输入没有违反程序的限制n使用
8、文件的结尾或标记终止输入,而不是用计数来终止输入n识别错误的输入(若有可能要恢复输入)Kernighan和Plauger给出的好的程序设计风格的规则n输入简易,输出自明n使用一致的输入格式n使输入容易校对n若可能,使用自由格式输入n使用自标识的输入,允许缺省,输出时反映这两者n确保在使用之前,所有变量已被置初值n在出现故障时不要停机n使用排错编译程序Kernighan和Plauger给出的好的程序设计风格的规则n用DATA语句或INITIAL属性置常数n用可执行的代码置变量初值n尽量注意由错误引起的分岔n注意在相等时转移的正确性n当一个循环从边上或底上退出到同一个地方时,必须十分小心n确保你的
9、代码“没有做什么优美方面的事情”n在边值处测试程序n人工核查某些答案Kernighan和Plauger给出的好的程序设计风格的规则n不要单独地进行浮点数相等比较n先保证正确,再提高速度n在提高速度之前,做好自动防止故障的措施n先保证清晰,再提高速度n不要为谋求“效率”上的少量增益而牺牲清晰n让你的编译程序做简单的优化n不要滥用再使用代码,取而代之的是改组n确保特殊情况是确实的特殊Kernighan和Plauger给出的好的程序设计风格的规则n保持简单,以提高速度n不要浪费代码而提高速度找一个较好的算法n使用工具装备你的程序,在“效率”改变以前测量(END)程序编码结构要求n采用结构化编码方法n
10、按以下22个特性构造(1)完整性n任何程序或控制段的开始和结束,必须包含在单一的结构化模块中。(2)功能n每个模块必须完成单一的定义良好的功能,模块的全部元素都是为了实现唯一的功能。n此外,模块实现的细节对其它模块来说应该是隐蔽的。如果实现的细节改变,直接受影响的只是实现功能的那个模块,并且只有该模块需要修改。(3)入口出口n每个模块一般要求单一入口和单一出口。处理完成后,模块必须返回到调用它的程序而不是其它模块。n接口(入口与出口条件和参数)必须明确表示和定义。(4)说明n模块的说明语句和数据语句应放在程序首部之后和第一个可执行语句之前,虽然允许每行可有多个数据说明,但应保证清晰地定义复杂的
11、数据结构。(5)常量n常量必须在程序的说明中定义,常量通常有数组规模、值、DO和FOR 循环中的循环数、数组下标、记录规模和行长度等。(6)变元n在调用语句中的变元一般不得包含算术或逻辑表达式。n每个变元必须由单一变量来表示。n在调用一个模块的过程中,变元的类型和个数必须与模块的形参相一致。n此外,必须标明调用过程中使用的形参。(7)幂n幂的指数必须用整数表示,即而不是。(8)混合方式运算n应避免使用混合运算的算术表达式,不能避免时应仔细计算表达式的值,以保证类型转换得到预期的结果,应对转换进行适当的注释。(9)转移n尽量少用无条件转移语句。如需使用,必须在同一程序单元内转移,并应向转移语句所
12、在点的前方转移。n允许使用为实现结构化程序设计所必需的转移指令。(10)错误处理a.必须记录所有错误的发生及处理情况,保存系统发生错误的全部记录,以利于后续错误情况的处理和分析;b.必须预先了解错误的潜在影响,并且在它们出现之前确定如何处理;c.应尽可能使错误不扩散,不引起连锁反应;d.当程序不能执行时,必须在中止前释放已取得的全部资源和结果。(11)范围检查n为保证变量值落在预期的范围内,必须进行范围检查。n如果变量值不在规定范围内,则必须进行适当的错误处理。n变量的定义域必须在设计时规定,在实现时声明,并在运行时检查。n必须进行范围检查的变量应包括:参数;数值下标;CASE结构中的变量参数
13、;循环结构中用作初值、增量和终值的变量。(12)序标和下标n循环序标参数和数值下标必须表示为整型的常量或变量。(13)循环终止n必须保证循环终止,终止条件不能靠对循环参数所作假设的正确性,而是靠对循环入口事前直接的验证。(14)标号和名字的使用n标号和名字必须有意义、一致并明显、唯一,不易混淆。(15)全局变量和共享变量n应避免使用全局或共享变量。当一个变量由两个或多个模块共享时,每个模块都必须正确地使用该变量。n由多个模块使用的变量应作为变元进行通信。限制变量的范围有助于掌握变量的准确含义。n当有明确的技术根据需要使用公共数据时,应有下列限制:a.仅使用可由名字访问的公用域;b.公用数据域的
14、长度和说明,对于使用它的每个模块都是相同的;c.可能时,应仅保留公用块的一个副本,而且必须用“INCLUDE”语句包容在每一个模块中而不是在模块中各自编码描述。(16)连接约定n如果模块是用汇编语言实现的,则必须定义和使用模块间通信的标准约定。目的是构造独立的、自包容的模块,它可以用良好定义的方法与其它模块通信。n应考虑的约定有:a.在将控制转给其它模块之前必须保护寄存器的内容,并在控制返回时恢复;b.通信必须通过变元素;c.必须有一个与调用模块返回地址进行通信的标准方法。(17)输入与输出n输入例程和输出例程必须集中在有限几个模块内。n将这些例程汇集到少数几个模块中有利于输入和输出数据的监控
15、。n此外,将这些例程限制在有限范围内可使修改更容易。(18)命名n代码和数据单元的名字必须体现它们的功能和内容。(19)程序首部n每个代码模块必须包含一个标准化的程序首部注释语句块,作为每个程序模块的内部源文档。它放在模块的首部,描述模块的功能、用途和操作要求。n程序首部应包括下面的信息:a.名称:包含用于标识模块的名称、版本标识符和入口。b.目的:包含模块目的功能的简要说明。程序首部n程序首部应包括下面的信息:c.输入输出,包含该模块所使用的每个文件名,并指明是向模块输入、还是输出、还是两者兼有。使用交互式屏幕的模块也应提供屏幕功能的说明。d.参数:提供模块所需的全部变元的定义以及模块的返回
16、值(输出参数)。参数定义必须包括:名字、数据类型、大小和功能。e.调用:提供该模块调用的全部例程的清单和调用该模块的全部例程的清单。f.全局数据:提供模块中使用的全部公用或全局数据的清单。程序首部n程序首部应包括下面的信息:g.限制:包含约束或限制模块性能特点的任何特殊或非常规因素的清单。h.异常结束:包含异常返回条件和动作的清单。i.方法:包含为实现模块的功能而使用的方法的详细说明。j.编程者:代码编制人名及所属机构。k.版本号及完成日期:当前的模块版本号和它的完成日期。l.修改记录:包含对该模块的修改人、所属机构、日期及对应的版本号。(20)行间注释n源程序体内的注释必须解释程序执行的处理
17、,必须指明每一个控制语句(有条件地更改一个数据值或语句的执行顺序的语句)的目的。语句:说明条件满足时执行动作的理由。语句:标明处理的记录或文件的性质。语句:说明执行动作的理由。语句:说明调用过程的理由。(21)注释比例n注释行数不得少于源程序总行数的。(22)缩进和分段n源代码必须清楚地缩进表达,以表明结构化程序段外形的控制范围,使编码的逻辑关系对应于程序列表的实际位置。n可执行语句限于每行一条。n超过一行的语句的后续部分应缩进该语句的第一行下面。n一行允许有多个数据说明。数据说明应使用某种逻辑顺序(例如字母顺序)排列。(23)模块规模n每个软件单元的源代码行数(不含注释行),平均不应超过行,
18、最大不应超过行。静态分析n静态分析是通过分析、但不执行软件的程序,找出其中的错误和疑点n静态分析手段之一,就是使用工具对软件单元甚至软件所有成分的源代码进行分析,获得以下主要信息:n语法错误信息;每个语句中标识符的引用分析,如变量、参数等;每个模块调用的子模块;未给初值的变量;已定义的但未使用的变量;未经说明或无用的标号;对任何一组输入数据均不可能执行到的代码段n可以根据所获信息对程序进行分析,发现其中可能存在的缺陷n还可以通过静态分析确定程序的分支、路径、转移等结构关系,为进行动态测试产生测试数据提供方便圈复杂度程序复杂性度量nMcCabe圈复杂度V(G)7n将程序流程图退化为程序图,将程序
19、流程图中每个处理符号都退化为一个点,箭头变成有向弧,调整使成为强连通图nV(G)=m-n+pnm=弧数nn=节点数np=分离部分的数目(连通图p=1)代码审查n代码审查是由代码审查员根据软件详细设计说明,按照规定的代码审查单,对被审查的程序代码逐条进行审查,以确保编码与设计的一致并确保编码的正确性n代码审查应着重审查错误代码而不是多余代码或代码的遗漏n各软件开发机构应根据自身情况和所开发的软件的特点,形成并不断补充完善自己使用的代码审查单通用的代码审查单格式:嵌套的IF是否已正确地缩进?注释准确并有意义吗?是否使用了有意义的标号?代码是否基本上与开始时的模块模式一致?是否遵循全套的编程标准?通
20、用的代码审查单入口和出口的连接:初始入口的最终出口正确吗?对另一个模块的每一次调用:全部所需的参数是否已传送给每一个被调用的模块?被传送的参数值是否正确地设置?通用的代码审查单程序语言的使用:是否使用一个或一组最佳的动词?模块中是否使用完整定义的语言的有限子集?存储器使用:每一个域在第一次使用前正确地初始化了吗?规定的域正确吗?每个域是否已由正确的变量类型声明?通用的代码审查单测试和转移:测试条件正确吗?用于测试的是正确变量吗?每个转移目标正确并至少执行一次吗?性能:逻辑是否被最佳地编码?提供的是一般的错误还是异常的例程?通用的代码审查单维护性:所提供的列表控制是否有利于提高可读性?标号和子程
21、序名符合代码的意义吗?逻辑:全部设计是否均已实现?编码是否做了设计所规定的内容?每个循环是否执行正确的次数?(END)调试n调试的任务:诊断和改正程序中的错误n调试的步骤:n根据迹象确定错误的正确位置n仔细分析研究以确定问题的原因并进行改正n确定错误位置占调试95%的工作量n错误改正后要进行回归测试n修改程序可能带来新的错误错误的特征和调试的困难n症状和原因可能是相隔很远的n症状可能在另一个错误被纠正后消失或暂时性消失n症状可能实际上并不是由“错误”引起的(如舍入误差)n症状可能是由不太容易跟踪的人工错误引起的n症状可能是和时间有关的,而不是处理问题n很难重新产生完全一样的输入条件(如实时应用
22、)n症状可能时时有时无的n症状可能是由分布在许多不同任务中的原因引起的调试技术n输出存储器内容n打印中间结果n自动工具(自动插装)调试策略n试探法n回溯法n对分查找法n归纳法n演绎法试探法n分析错误征兆n猜想故障的大致位置n采用某些调试技术获得程序中被怀疑地方附近的信息n试探法通常是缓慢而低效的回溯法n检查错误征兆,确定最先发现“症状”的地方n用人工沿程序的控制流往回追踪源程序代码,直到找出错误根源或确定故障范围为止n另一种形式是正向追踪,使用输出语句检查一系列中间结果,以确定最先出现错误的地方n回溯法比较适用于小程序,大规模程序使彻底回溯不可能对分查找法n如果已经知道每个变量在程序内若干关键
23、点的正确值,则可以用赋值语句或输入语句在程序中点附近“注入”这些变量的正确值,然后检查程序的输出n如果输出结果正确,故障在程序的前半部分;反之在程序的后半部分n重复使用直到定位或范围小到容易诊断归纳法n从个别推断一般,从线索出发,通过分析线索关系找出故障n四个步骤:n收集有关的数据:列出已经知道的关于程序哪些事做得对哪些事做得不对的一切数据n组织数据:整理数据,发现规律,发现矛盾,即在什么条件下出现错误,什么条件下不出现错误n导出假设:分析线索之间的关系,提出故障的假设n证明假设:解释所有原始的测试结果演绎法n从一般原理和前提出发,经过推导的出结论n从所有可能的原因和假设出发,一一排除而得到结果n四个步骤:n设想可能的原因n用已有的数据排除不正确的假设n精化余下的假设:具体化和定位n证明余下的假设修改的问题n在改错时回答以下问题:n这个错误在程序的其它地方也会产生吗?举一反三n将要进行的修改可能会引发的“下一个错误”是什么?消除影响n为了防止这个错误,首先应当做什么?缺陷预防谢谢!68389085(O)68389504(H)
限制150内