201871010118-唐敬博实验三软件工程结对项目
|项目| 内容|
| ---- | ---- | ---- |
|课程班级博客链接| https://edu.cnblogs.com/campus/xbsf/2018CST/|
|这个作业要求链接| https://www.cnblogs.com/nwnu-daizh/p/14604444.html|
|我的课程学习目标| (1)体验软件项目开发中的两人合作,练习结对编程(Pair programming)。(2)掌握Github协作开发程序的操作方法。|
|这个作业在哪些方面帮助我实现学习目标| (1)通过阅读邹欣老师的书理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念。(2)通过两人合作、结对编程理解领航员和驾驶员两种角色关系,采用汉堡包法实施项目结对中两个人的沟通。(3)学习遗传算法。|
|结对方学号-姓名| 201871010136-赵艳强|
任务一:
阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;
代码风格规范:
缩进:4个空格。不用 Tab键的理由是Tab键在不同的情况下会显示不同的长度。4个空格的距离从可读性来说正好。
行宽:行宽必须限制,但是以前有些文档规定的80字符行宽太小了(以前的计算机/打字机显示行宽为80字符),现在时代不同了,可为100字符。
括号:在复杂的条件表达式中,用括号清楚地表示逻辑优先级。
断行与空白的{ }行:不同的语句(Statement)放在一行中,会使程序调试(DeBug)非常不方便。
分行:不要把多行语句放在一行上。
命名:让程序员一眼就能看出变量的类型,避免在使用中出错。
下划线问题:下划线用来分隔变量名字中的作用域标注和变量的语义,如:一个类型的成员变量通常用m_来表示。移山公司规定下划线一般不用在其他方面。
大小写问题:由多个单词组成的变量名,如果全部都是小写,很不易读,一个简单的解决方案就是用大小写区分它们。
注释:注释是用来解释程序做什么(What),为什么这样做(Why),以及要特别注意的地方的。复杂的注释应该放在函数头,很多函数头的注释都是解释参数的类型等的,如果程序正文已经能够说明参数的类型in/out等,就不要重复!注释也要随着程序的修改而不断更新,一个误导的(Misleading)注释往往比没有注释更糟糕。另外,注释(包括所有源代码)应只用ASCII字符,不要用中文或其他特殊字符,它们会极大地影响程序的可移植性。在现代编程环境中,程序编辑器可以设置各种好看的字体,我们可以使用不同的显示风格来表示程序的不同部分。注意: 有些程序设计语言的教科书对于基本的语法有详细的注释, 那是为了教学的目的, 不宜在正式项目中也这么做。
代码设计规范:
函数:现代程序设计语言中的绝大部分功能,都在程序的函数(Function, Method)中实现,关于函数最重要的原则是:只做一件事,但是要做好。
goto:函数最好有单一的出口,为了达到这一目的,可以使用goto。只要有助于程序逻辑的清晰体现,什么方法都可以使用,包括goto。
错误处理:包括参数处理、断言
如何处理C++中的类:
类:
使用类来封装面向对象的概念和多态(Polymorphism)。
避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要用类来实现。
对于有显式的构造和析构函数,不要建立全局的实体,因为你不知道它们在何时创建和消除。
只有在必要的时候,才使用“类”。
Class vs. Struct:
如果只是数据的封装,用Struct即可。
公共/保护/私有成员Public、Private和Protected:
按照这样的次序来说明类中的成员:public、protected、private
数据成员:
数据类型的成员用m_name说明。
不要使用公共的数据成员,要用inline访问函数,这样可同时兼顾封装和效率。
虚函数Virtual Functions:
使用虚函数来实现多态(Polymorphism)。
只有在非常必要的时候,才使用虚函数。
如果一个类型要实现多态,在基类(Base Class)中的析构函数应该是虚函数。
构造函数Constructors:
不要在构造函数中做复杂的操作,简单初始化所有数据成员即可。
构造函数不应该返回错误(事实上也无法返回)。把可能出错的操作放到HrInit()或FInit()中。
析构函数:
把所有的清理工作都放在析构函数中。如果有些资源在析构函数之前就释放了,记住 要重置这些成员为0或NULL。
析构函数也不应该出错。
New和Delete:
如果可能,实现自己的New/Delete,这样可以方便地加上自己的跟踪和管理机制。自己的New/Delete可以包装系统提供的New/Delete。
检查New的返回值。New不一定都成功。
释放指针时不用检查NULL。
运算符(Operators):
在理想状态下,我们定义的类不需要自定义操作符。只有当操作符的确需要时。
运算符不要做标准语义之外的任何动作。例如,“==”的判断不能改变被比较实体的状态。
运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。
当你拿不定主意的时候,用成员函数,不要用运算符。
异常(Exceptions):
异常是在“异乎寻常”的情况下出现的,它的设置和处理都要花费“异乎寻常”的开销,所以不要用异常作为逻辑控制来处理程序的主要流程。
了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销。
当使用异常时,要注意在什么地方清理数据。
异常不能跨过DLL或进程的边界来传递信息,所以异常不是万能的。
类型继承(Class Inheritance):
当有必要的时候,才使用类型继承。
用Const标注只读的参数(参数指向的数据是只读的,而不是参数本身)。
用Const标注不改变数据的函数。
代码复审
代码复审的步骤:
代码必须成功地编译,在所有要求的平台上,同时要编译DeBug| Retail版本。编译要用团队规定的最严格的编译警告等级(例如C/C++中的W4)。
程序员必须测试过代码。什么叫测试过?最好的方法是在DeBugger中单步执行。同时也可以加上OutputDeBugString等输出来监视程序的控制流。
程序员必须提供新的代码,以及文件差异分析工具。Windiff或VSTS自带的工具都可以。VSTS中可以通过Shelveset来支持远程代码复审。
复审者可以选择面对面的复审、独立复审或其他方式。
在面对面的复审中,一般是开发者控制流程,讲述修改的前因后果。但是复审者有权在任何时候打断叙述,提出自己的意见。
复审者必须把反馈意见逐一提出。注意,复审者有权提出很多看似吹毛求疵的问题,复审者不必每一件事都要亲自调查,开发者有义务给出详尽的回答。
开发者必须负责让所有的问题都得到满意的解释或解答,或者在TFS中创建新的工作项以确保这些问题将来会得到处理。
对于复审的结果,双方必须达成一致的意见。
复审的目的在于:
找出代码的错误。
发现逻辑错误,程序可以编译通过,但是代码的逻辑是错的。
发现算法错误,比如使用的算法不够优化。
发现潜在的错误和回归性错误——当前的修改导致以前修复的缺陷又重新出现。
发现可能改进的地方。
教育(互相教育)开发人员,传授经验,让更多的成员熟悉项目各部分的代码,同时熟悉和应用领域相关的实际知识。
结对编程:
在结对编程模式下,一对程序员肩并肩地、平等地、互补地进行开发工作。两个程序员并排坐在一台电脑前,面对同一个显示器,使用同一个键盘,同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起单元测试,一起集成测试,
一起写文档等。
结对编程有如下的好处:
在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感。
在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄。
在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享。
如果运用得当,结对编程能得到更高的投入产出比(Return of Investment)
任务二:对结对方的项目成果进行评价
对项目博文作业进行阅读并进行评论
认真阅读了结对方的项目博文作业,并从博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因四个方面进行了评论。
复审同伴项目代码
概要部分:
代码基本符合需求,设计考虑的不够周全,同伴的代码中包括动态规划算法和回溯算法求解0-1背包问题的过程,用户可以选择其中的一种算法进行求解,但是要求的部分功能还未实现。代码的可读性比较好,且易于维护。
设计规范部分:设计遵从项目中常用的模式,存在一小部分无用的代码可以清除。
代码规范部分:修改的部分符合代码标准和风格。
具体代码部分:对于调用的外部函数检查了返回值,参数传递无错误。
可读性:代码可读性较好,而且有必要的注释,易于理解。
任务三:采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台
需求分析陈述
通常用户处理数据时的数据量比较大,而且不同的用户可能会使用不同的方法求解问题的解,所以,为了方便用户使用不同的方法求出0-1背包问题的最优解,提高处理大量数据的效率,我们需要设计开发一款D{0-1}KP 实例数据集算法实验平台。
D{0-1}KP 实例数据集算法实验平台具有的功能如下:
平台基础功能:实验二 任务3;
D{0-1}KP 实例数据集需存储在数据库;
平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;
人机交互界面要求为GUI界面(WEB页面、APP页面都可);
查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);
附加功能:除(1)-(5)外的任意有效平台功能实现。
软件设计说明:
在个人项目中绘制了一组数据的散点图,实现了对价值与重量之比进行排序,完成了用动态规划算法求解0-1背包问题,并计算出了运行的时间,此次结对项目是在个人项目的基础上进行了进一步的完善。
增加使用回溯算法求解0-1背包问题
back_tracking函数:
进行回溯,在搜索的过程中可进行剪枝操作。当不选择此物品时,若此时所能达到的最大价值小于当前的最优价值,则进行剪枝操作,即不在继续向下搜索这个结点的子树。如果选择此物品,则判断背包的剩余重量是否大于当前物品的重量,如果小于当前物品的重量,则不装入。
此函数最后返回记录物品是否装入的数组与最优价值。
上界函数bound:
判断当前物品下所能达到的最大价值。
对动态规划算法进行修改
在个人项目中,动态规划算法求解的最大价值是正确的,但是选择的物品出现了错误,进行修改之后能求得正确的结果。
可以选择不同的方法求解问题
从键盘输入一个字符,若它的值为”1“,则使用动态规划法求解,若为”2“就用回溯法求解,否则输出一条错误提示语句。
将求解的结果保存在txt文件中
学习并尝试使用遗传算法求解0-1背包问题
GA是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。遗传算法已被人们广泛地应用于组合优化、机器学习、信号处理、自适应控制和人工生命等领域。
结对作业的PSP
| 任务内容 | 计划共完成需要的时间(h) | 实际完成需要的时间(h) |
|---|---|---|
| 计划 | 0.5 | 0.5 |
| • 估计这个任务需要多少时间 | 0.5 | 0.5 |
| 开发 | 64.5 | 74 |
| • 需求分析 | 1 | 1.5 |
| • 生成设计文档 | 2 | 2 |
| • 设计复审 | 3 | 3.5 |
| • 代码规范 | 1 | 2 |
| • 具体设计 | 2.5 | 3 |
| • 具体编码 | 35 | 40 |
| • 代码复审 | 8 | 7 |
| • 测试 | 12 | 15 |
| 报告 | 1.9 | 2.6 |
| • 测试报告 | 0.3 | 0.5 |
| • 计算工作量 | 0.6 | 0.6 |
| • 事后总结及过程改进计划 | 1 | 1.5 |
| 描述结对的过程,提供两人在讨论、细化和编程时的结对照片(非摆拍) | ||
![]() |


浙公网安备 33010602011771号