魏娜娜-软件工程实验三
项目 | 内容 |
---|---|
课程班级博客链接 | https://edu.cnblogs.com/campus/xbsf/2018CST/ |
这个作业要求链接 | https://www.cnblogs.com/nwnu-daizh/p/14604444.html |
我的课程学习目标 | 体验软件项目开发中的两人合作,练习结对编程。掌握Github协作开发程序的操作方法 |
这个作业在哪些方面帮助我实现学习目标 | 在结对编程中,学会了与结对者互相沟通,团队合作,提升编程技能 |
结对方学号-姓名 | 201871030121-马艳 |
结对方本次博客作业链接 | https://i.cnblogs.com/posts/edit |
本项目Github的仓库链接地址 | https://github.com/we446/222/commit/4768834cc87fae867e55eb5fc8dced8cedd7c374 |
任务一
阅读《现代软件工程-构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;
-
代码规范
-
什么是代码规范?
-
代码风格规范。主要是文字上的规定,看似表面文章,实际上非常重要。
代码设计规范。牵涉到程序设计、模块之间的关系、设计模式等方方面面,这里有不少与具体程序设计语言息息相关的内容(如C/C++/Java/C#),但是也有通用的原则,这里主要讨论通用的原则。
-
-
-
代码风格规范
原则:简单,易读,无二义性;
-
其中代码风格规范主要包括:
-
缩进:用4个空格键而不是Tab键,因为在不同情况下Tab键会显示不同的长度,4个空格从可读性来说更好
-
行宽:行宽必须限制,现在可为100字符;
-
括号:用括号可表示优先级
-
断行与空白的{ }行:使程序更加清晰,更好执行
-
分行:不要把多条语句放在同一行
-
命名:匈牙利命名法,但在有些地方不适合
-
下划线问题:下划线用来分隔变量名字中的作用域标注和变量的语义
-
大小写问题:一个通用的做法是:所有的类型/类/函数名都用Pascal形式,所有的变量都用Camel形式。
类/类型/变量:名词或组合名词,如Member、ProductInfo等。
函数则用动词或动宾组合词来表示,如get/set; RenderPage()。
-
注释:是用来解释程序做什么(What),为什么这样做(Why),以及要特别注意的地方的
-
-
-
代码设计规范
-
代码设计规范不光是程序书写的格式问题,而且牵涉到程序设计、模块之间的关系、设计模式等方方面面
-
函数:现代程序设计语言中的绝大部分功能,都在程序的函数(Function, Method)中实现,关于函数最重要的原则是:只做一件事,但是要做好
-
goto:只要有助于使程序逻辑清晰,什么方法都可以用,包括goto
-
错误处理:包括参数处理和断言;
-
在DeBug版本中,所有的参数都要验证其正确性。在正式版本中,从外部(用户或别的模块)传递过来的参数要验证其正确性。
-
如何验证正确性?那就要用Assert(断言)。断言和错误处理是什么关系?
当你觉得某事肯定如何,你可以用断言。
-
-
如何处理C++中的类
-
类:使用类来封装面向对象的概念和多态(Polymorphism)。
避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要用类来实现。
对于有显式的构造和析构函数,不要建立全局的实体,因为你不知道它们在何时创建和消除。
只有在必要的时候,才使用“类”。
-
Class vs. Struct:如果只是用数据的封装,用struct即可
-
公共/保护/私有成员Public、Private和Protected
-
数据成员
-
虚函数Virtual Functions
-
构造函数Constructors
-
析构函数
-
New和Delete
-
运算符(Operators)
-
异常(Exceptions)
-
类型继承(Class Inheritance)
-
-
-
-
代码复审
-
复审的目的
-
(1)找出代码的错误。如:
a. 编码错误,比如一些能碰巧骗过编译器的错误。
b. 不符合项目组的代码规范的地方。
(2)发现逻辑错误,程序可以编译通过,但是代码的逻辑是错的。
(3)发现算法错误,比如使用的算法不够优化。
(4)发现潜在的错误和回归性错误——当前的修改导致以前修复的缺陷又重新出现。
(5)发现可能改进的地方。
(6)教育(互相教育)开发人员,传授经验,让更多的成员熟悉项目各部分的代码,同时熟悉和应用领域相关的实际知识。
-
了解了在代码复审中应该做什么,步骤,复审后还应该做什么
-
-
-
结对编程的概念
- 结对编程随着敏捷开发思想的兴起而广为人知, 然而这种实践早已有之。 在 1987年, Intuit 公司 (当时只是一个刚刚创业的个人财务管理软件公司)向顾客宣布在 4 月份提供新版本的软件 (4月15日是美国报税的截止日期)。 但到了 3 月份的时候, 公司仅有的两个技术人员发现项目还是大大落后于预期, 于是这两人在 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)对资源的利用,是在哪里申请,在哪里释放的?有无可能存在资源泄漏(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有优化的空间?对空间的优化较好,无数据库的访问链接
6)数据结构中有没有用不到的元素? 没有
任务三
采用两人结对编程方式,设计开发一款D{0-1}KP 实例数据集算法实验平台,使之具有以下功能:
(1)平台基础功能:实验二 任务3;
(2)D{0-1}KP 实例数据集需存储在数据库;
(3)平台可动态嵌入任何一个有效的D{0-1}KP 实例求解算法,并保存算法实验日志数据;
(4)人机交互界面要求为GUI界面(WEB页面、APP页面都可);
(5)查阅资料,设计遗传算法求解D{0-1}KP,并利用此算法测试要求(3);
(6)附加功能:除(1)-(5)外的任意有效平台功能实现。
任务四
-
需求分析:背包问题是一个经典的组合优化问题,有着广泛而重要的应用背景。{0-1}背包问题是最基本的KP问题形式,它的一般描述为:从若干具有价值系数与重量系数的物品(或项)中,选择若干个装入一个具有载重限制的背包,如何选择才能使装入物品的重量系数之和在不超过背包载重前提下价值系数之和达到最大?
在处理到第i个物品时,可以假设一共只有i个物品,如果前面i-1个物品的总的最大价值已经定下来了,那么第i个物品选不选将决定这1~i个物品能带来的总的最大价值。刚刚是自顶向下,接下来反过来自底向上,第1个物品选不选可以轻松地用初始化解决,接下来处理第i个物品时,假设只有2个物品就好,那他处理完后前2个物品能带来的最大总价值就确定了,这样一直推下去,就可以推出前n个物品处理完后能带来的最大总价值。
对于每个背包,都只有0和1的情况,也就是拿或者不拿两种情况
如果拿:那么空间就会减一点,比如说现在在考虑第i个物品拿不拿,如果说当前剩余空间为j,那么拿了之后空间就变为j-c[i],但是总价值却会增加一点,也就是增加w[i]
如果不拿:那么空间不会变,还是j,但是总价值也不会变化。
-
软件设计说明:分析遗传算法,基于实验二来扩展其功能,连接数据库,设计人机交互界面,在编程中使用结对编程的方式,然后代码复审
-
核心代码展示
主要代码:
while iteration < self.iteration: # 设置迭代次数300 parents = self.selection(init_population) # 选择后的父代 children = self.crossover(parents) mutation_children = self.mutation(children) init_population = mutation_children f_set = [] # 求出每一步迭代的最大值 for init in range(init_population.shape[1]): f_set_tem = self.fitness_function(init_population[:, init]) f_set.append(f_set_tem) f_set = max(f_set) f_set_plot.append(f_set) iter_plot.append(iteration) iteration = iteration+1 print("第%s进化得如何******************************************" % iteration) f_average = self.fitness_average(init_population) f_plot.append(f_average) print(f_set) # f_accumulation = f_accumulation + f # f_print = f_accumulation/(iteration + 1) # print(f_print) self.plot_figure(iter_plot, f_plot, f_set_plot)
def usr_sign_up(): #确认注册时的相应函数 def signtowcg(): #获取输入框内的内容 nn=new_name.get() np=new_pwd.get() npf=new_pwd_confirm.get() #本地加载已有用户信息,如果没有则已有用户信息为空 try: with open('usr_info.pickle','rb') as usr_file: exist_usr_info=pickle.load(usr_file) except FileNotFoundError: exist_usr_info={} #检查用户名存在、密码为空、密码前后不一致 if nn in exist_usr_info: tk.messagebox.showerror('错误','用户名已存在') elif np =='' or nn=='': tk.messagebox.showerror('错误','用户名或密码为空') elif np !=npf: tk.messagebox.showerror('错误','密码前后不一致') #注册信息没有问题则将用户名密码写入数据库 else: exist_usr_info[nn]=np with open('usr_info.pickle','wb') as usr_file: pickle.dump(exist_usr_info,usr_file) tk.messagebox.showinfo('欢迎','注册成功') #注册成功关闭注册框 window_sign_up.destroy()
-
截图
-
描述结对过程
首先我们确定了结对的伙伴,并进行了沟通,因为在一个宿舍,所以主要是在一起合作,我们水平差不多,所以编写代码两个人一起合作,然后一起代码复审,在复审的时候,基本就是我复审她写的内容,她复审我写的内容,下面是我们在微信沟通的截图:
-
此次作业的PSP
任务内容 计划共完成需要的时间 实际完成的时间 计划 460 510 估计这个任务需要多长,并规划大致工作步骤 20 30 开发 40 30 需求分析 20 10 生成设计文档 30 40 设计审核 30 20 代码规范 20 20 具体设计 50 60 具体编码 120 120 代码复审 20 30 测试 30 40 报告 20 30 测试报告 30 40 计算工作量 10 20 事后总结,并提出过程改进计划 20 20 -
小结感受
在本次结对编程项目中,我认识到了与结对伙伴如何沟通交流,如何结对编程,学到很多知识,但是还是有很多地方不会,或者是尝试好多次都无法正常的运行,也提升了自己解决问题的能力。通过与自己的结对伙伴交流合作,也体会到合作团结沟通的重要性。