项目 | 内容 |
---|---|
课程班级博客链接 | 班级博客 |
这个作业要求链接 | 作业要求 |
我的课程学习目标 | (1)理解并掌握代码风格及设计规范; (2)通过任务3进行协作开发,尝试进行代码复审,在进行同伴复审的过程中体会结对编程; (3)在学习D{0-1}问题的解法的同时掌握程序设计的模块化开发,并熟悉PSP流程。 (4)掌握Github协作开发的操作方法。 |
这个作业在哪些方面帮助我实现学习目标 | (1)通过对实验二博客进行阅读评价,发现同伴的不足,同时可以对自己实验二的部分遗留问题得到解决; (2)通过阅读《构建之法》第3,4章,对代码风格及设计规范有了了解,掌握代码复审以及结对编程; (3)通过背包问题的程序开发,掌握了软件项目个人开发流程以及Github发布软件项目的操作方法。 (4)结对过程中运用汉堡包发进行沟通,有利于项目的推进。 |
结对方学号-姓名 | 201871010108-高文利 |
结对方本次博客作业链接 | 高文利-实验三 |
一.实验内容与步骤
任务1:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;
1.代码风格规范主要是文字上的规定,看似表面文章,实际上非常重要。
- 代码设计规范牵涉到程序设计、模块之间的关系、设计模式等方方面面,这里有不少与具体程序设计语言息息相关的内容,但是也有通用的原则,这里主要讨论通用的原则。
- 原则:简单,易读,无二义性;
- 其中代码风格规范主要包括:
- 缩进:用4个空格键而不是Tab键,因为在不同情况下Tab键会显示不同的长度,4个空格从可读性来说更好
- 行宽:行宽必须限制,现在可为100字符;
- 括号:用括号可表示优先级
- 断行与空白的{ }行:使程序更加清晰,更好执行
- 分行:不要把多条语句放在同一行
- 命名:匈牙利命名法,但在有些地方不适合
- 下划线问题:下划线用来分隔变量名字中的作用域标注和变量的语义
- 大小写问题:一个通用的做法是:所有的类型/类/函数名都用Pascal形式,所有的变量都用Camel形式。
- 类/类型/变量:名词或组合名词,如Member、ProductInfo等。
- 函数则用动词或动宾组合词来表示,如get/set; RenderPage()。
- 注释:是用来解释程序做什么(What),为什么这样做(Why),以及要特别注意的地方。
- 其中代码风格规范主要包括:
2.代码设计规范
- 代码设计规范不光是程序书写的格式问题,而且牵涉到程序设计、模块之间的关系、设计模式等方方面面
- 函数:最重要的原则:只做一件事,并且要最好。
- goto:函数最好有单一的出口,为达到这一目的,可以使用goto。只要有助于程序逻辑的清晰体现,什么方法都可以使用,包括goto。
- 错误处理:当程序的主要功能实现后,给代码加一些错误处理。
- 参数处理:在debug版本中,所有的参数都要验证其正确性。在正式版本中,对从外部(用户或别的模块)传递过来的参数,要验证其正确性。
- 断言:使用断言来验证正确性。
- 如何处理c++中的类:处理关于异常的部分,大部分其他原则对C#也使用。
- 类:使用类来封装面向对象的概念和多态。避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要用类来实现,对于有显式的构造和析构函数的类,不要建立全局的实体,因为你不知道它们在何时创建和消除。仅在必要时,才使用“类”。
- class vs.struct:如果只是数据的封装,用struct即可。
- 公共/保护/私有成员:按照这样的次序来说明类中的成员: public、 protected. private。
- 数据成员:数据类型的成员用m_ name说明。不要使用公共的数据成员,要用inline访问函数,这样可兼顾封装和效率。
- 虚函数 :使用虚函数来实现多态,仅在很有必要时,才使用虚函数,如果一个类型要实现多态,在基类中的析构函数应该是虚函数。
- 构造函数:不要在构造函数中做复杂的操作,简单初始化所有数据成员即可。构造函数不应该返回错误(事实上也无法返回)。把可能出错的操作放到HrInit()或FInit()中。
- 运算符:在理想状态下,我们定义的类不需要自定义操作符。确有必要时,才会自定义操作符。运算符不要做标准语义之外的任何动作。运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。当你拿不定主意的时候,用成员函数.不要用运算符。
- 异常:异常是在“异乎寻常”的情况下出现的,它的设置和处理都要花费“异乎寻常”的开销,所以不要用异常作为逻辑控制来处理程序的主要流程。了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销。当使用异常时,要注意在什么地方清理数据。异常不能跨过DLL或进程的边界来传递信息,所以异常不是万能的。
3.代码复审:看代码是否在代码规范的框架中正确地解决了问题。(自我复审、同伴复审、团队复审)
- 代码复审的目的:
- 找出代码的错误。
- 发现逻辑错误,程序可以编译通过,但是代码的逻辑是错误的。
- 发现算法错误。
- 发现潜在的错误和回归性错误--当前的修改导致以前修复的缺陷又重新出现。
- 可能需要改进的地方。
- 代码复审的分类:
- 自我复审:用同伴复审的标准来要求自己。不一定最有效, 因为开发者对自己总是过于自信。如果能持之以恒,则对个人有很大好处。
- 同伴复审:简单易行。
- 团队复审:有比较严格的规定和流程,适用于关键的代码,以及复审后不再更新的代码。覆盖率高——有很多双眼睛盯着程序,但效率可能不高(全体人员都要到会)。
- 代码复审的核查表
- 概要部分
- 设计规范部分
- 代码规范部分
- 具体代码部分
- 效能
- 可读性
- 可测试性
- 开发中的复审包括:设计复审、代码复审、测试技术复审和文档复审。
- 在结对编程过程中,代码被不断的复审,可以避免牛仔式的编程,可以帮助团队成员建立集体拥有代码的意识。
4.结队编程:是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。
- 角色:驾驶员:控制键盘输入;领航员:起到领航、提醒的作用。
- 好处:(1)在开发层次,可以提供更好的设计质量和代码质量,两人合作解决问题的能力更强。
(2)对开发人员,带来更多的信心,高质量的产出带来更高的满足感。
(3)企业管理层次上,有效地交流,相互学习和传递经验,分享知识,取得更高的投入产出比。 - 目的:每人在各自独立设计、实现软件的过程中不免要犯这样那样的错误。在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。
任务2:两两*结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价,具体要求如下:
(1)对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。
- 结队方博客链接:高文利-实验二
- 进行评论:
(2)克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
- 代码进行阅读和测试:
- 进程代码复审,未发现大的语法问题,对一些细节问题进行了改进。
- 核查表内容:
- 概要部分
1)代码符合需求和规格说明么?————基本符合
2)代码设计是否考虑周全?————整体功能已实现,细节部分需要注意。
3)代码可读性如何?————可读性较好,应进一步加强代码设计规范。
4)代码容易维护么?————不是特别容易
5)代码的每一行都执行并检查过了吗?————已检查 - 设计规范部分
1)设计是否遵从已知的设计模式或项目中常用的模式?————是
2)有没有硬编码或字符串/数字等存在?————没有
3)代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到 Win64 ) ?————没有
4)开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现?————没有
5)有没有无用的代码可以清除?————存在一小部分,已修改。 - 代码规范部分
- 修改的部分符合代码标准和风格吗?————修改的部分符合代码标准和风格
- 具体代码部分
1)有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常?————没有
2)参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数?————没有
3)边界条件是如何处理的?switch语句的default分支是如何处理的?循环有没有可能出现死循环?————试运行时没有出现死循环
4)有没有使用断言(Assert)来保证我们认为不变的条件真的得到满足?————没有使用
5)对资源的利用,是在哪里申请,在哪里释放的?有无可能存在资源泄漏?有没有优化的空间?————对空间的优化较好,无数据库的访问链接
6)数据结构中有没有用不到的元素? ————未发现
- 概要部分
(3)依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
- 由于编程能力不是很强,未能进行成功修改。
任务3:采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台;
- 功能设计:
- 平台基础功能:实验二 任务3;
- D{0-1}KP 实例数据集需存储在数据库;
- 平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;
- 人机交互界面要求为GUI界面(WEB页面、APP页面都可);
- 查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);
- 附加功能:除(1)-(5)外的任意有效平台功能实现。
- 实现过程:
-
需求分析陈述:包含背包问题,遗传算法等,在线绘制散点图、回溯算法求解、动态算法求求解。
- 后台要能够从给定的文件中读取出正确的数据并保存到数据库
- 能够根据数据在线绘制散点图
- 实现java后台解决D{0-1}背包问题的动态规划和回溯算法
- 后台将求解后的数据写入文件并保存,前端展示文件下载阅览,在运行之后,将运行结果保存到文件然后返回前端
- 后台编写遗传算法求解D{0-1}KP
-
软件设计说明。
- 在背包问题的基础上理解遗传算法:利用遗传算法求解D{0-1}KP问题,可假设一个项集的物品扩展为A、B、C三个物品,将三个物品间两两组合的折扣关系分别假设为物品D、E、F,选择三个物品时的折扣关系假设为物品G。在该项集中选择情况包含:全部不选、选择物品A、选择物品B、选择物品C、选择物品D(物品A和B的组合)、选择物品E(物品A和C的组合)、)、选择物品F(物品B和C的组合)以及选择物品G(物品A、B和C的组合)共八种情况。在同一时刻,每个项集的选择只能是八种情况之一。
- 遗传算法:基于随机的进化算法;希望通过多次将高质量的个体繁衍后,生出所需要的个体。随机:新的解会在原有的解上发生随机变化。
- 基本思想:遗传算法的搜索从一个被称作种群的候选解集开始,新的种群由旧的种群中产生以期得到更好的种群。从旧种群中按照解的适应度来选择解以产生新的解;适应度越大,解被选择生成后代的机率也越大。这个从已有种群中选择双亲并产生后代的迭代过程持续到遗传算法的停止条件满足为止。
遗传算法流程图:
软件实现及核心功能代码展示。
描述结对的过程(进行讨论与沟通)
提供此次结对作业的PSP。(4分)
-
PSP2.1 | 任务内容 | 划共完成需要的时间(min) | 实际完成需要的时间(min) |
---|---|---|---|
Planning | 计划 | 60 | 10 |
· · Estimate | · 估计这个任务需要多少时间,并规划大致工作步骤 | 60 | 10 |
development | 开发 | 700 | 880 |
· · Analysis | · 需求分析 (包括学习新技术) | 40 | 20 |
· · Design Spec | · 生成设计文档 | 25 | 20 |
· · Design Review | · 设计复审 (和同事审核设计文档) | 20 | 20 |
· · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 40 |
· · Design | 具体设计 | 25 | 40 |
· · Coding | · 具体编码 | 290 | 300 |
· · Code Review | · 代码复审 | 40 | 40 |
· · Test | · 测试(自我测试,修改代码,提交修改) | 25 | 50 |
Reporting | 报告 | 130 | |
· · Test Report | · 测试报告 | 70 | |
· · Size Measurement | · 计算工作量 | 35 | |
· · Postmortem & Process Improvement Plan | · 事后总结 ,并提出过程改进计划 | 25 |
- 小结感受:两人合作真的能够带来1+1>2的效果吗?通过这次结对合作,请谈谈你的感受和体会。(4分)
通过本次项目的完成,体验了软件项目开发中的两人合作,并练习了结对编程。对于项目而言,团队合作极大地缩小了项目周期,并且较个人项目而言,项目的完成性与准确性较高,对于项目的整体完成有很大的帮助;对于团队中的个人而言,可以在结对过程中相互监督每一阶段任务的完成,相互检查完成情况,及时发现对方与自己的不足并进行改进,从而使结对双方共同进步;所以两人合作,可以达到共赢,就一定可以带来1+1>2的效果。