项目 | 内容 |
---|---|
课程班级博客链接 | 班级博客 |
作业要求链接 | 作业要求 |
我的课程学习目标 | 1.能够在这次的结对编程中体验软件项目开发中的两人合作,并能够很好地练习结对编程。 2.掌握Github协作开发程序的操作方法。 3.进一步掌握PSP流程 |
这个作业在哪些方面帮助我实现学习目标 | 1.体验软件项目开发中的两人合作,练习结对编程 2.掌握Github协作开发程序的操作方法 3.进一步加强GitHub的练习与使用 4.使用并熟悉java语言的编写 |
结对方学号-姓名 | 201871010107-公海瑜 |
结对方本次博客作业链接 | 结对方博客链接 |
一、实验目的与要求
(1)体验软件项目开发中的两人合作,练习结对编程(Pair programming)。
(2)掌握Github协作开发程序的操作方法。
二、实验内容和步骤
任务1:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;
软件开发流程不仅仅包括团队的流程,还包括了个人的开发流程,团队是由每个人组成的,在软件开发流程中,是由每一个团队成员具体的个人在做开发,测试,UI,管理,交流等工作。在软件工程的术语中,我们把这些单个的成员叫做IC。
- IC在一次团队流程中的流程如下:
1.通过交流,实验,快速原型等方法,理解问题,需求或任务。
2.提出多种解决办法并估计工作量(其中包括寻找以前的解决方案,因为很多工作室重复性的)
3.与相关角色交流解决问题的提案,决定一个可行的方案
4.执行,把想法变成实际中能工作的代码,同时验证方案的可行性和其他特性(程序的效能)
5.和团队的其他角色合作,在测试环境中测试实现方案,修复缺陷。
6.在解决方案发布出去之后,对结果负责
- 作为初级软件工程师(SDE)的成长需要:
1.积累软件开发相关的知识,提升技术技能
2.积累问题领域的知识和经验
3.对通用的软件设计思想和软件工程思想的理解
4.提升职业技能(自我管理,表达和交流,与人合作,按质按量完成任务的执行力)
5.实际成果
- 软件开发的工作量和质量衡量方法(PSP的四个因素)
1.任务有多大(代码行数/功能点个数)
2.花了多少时间?
3.质量如何?(交付的代码中有多少缺陷)
4.是否按时交付?(从标准方差上看,因为团队工作中需要的是稳定,一致的交付时间)
- 团队对个人的期望
1.交流
2.说到做到
3.接收团队赋予的角色并按角色要求工作
4.全力投入团队的活动。
5.按照团队流程的要求工作
6.做好每次的准备工作
7.理性地工作
-
代码风格规范:原则:简明,易读,无二义性。
1.缩进:4个空格。
2.行宽:可以限定100字符。
3.括号:在复杂的条件表达式中,用括号清楚地表达逻辑优先级。
4.断行与空白的{}行:格式D:每个“{”和“}”都独占一行。
5.分行:不要把多条语句放在一行上。
6.命名:在变量名中不要提到类型或者其他语法方面的描述。避免过多的描述。如果信息可以从上下文中得到,那么此类信息就不必写在变量名中。避免可要不可要的修饰词。
7.下划线:下划线用来分隔名字中作用域标注和变量的语义。
8.大小写:由多个单词组成的变量名,如果全部都是小写,很不易读,一个简单的解决方案就是用大小写区分它们。
Pascal——所有单词的第一个字母都大写。 Camel——第一个单词全部小写,随后单词随Pascal形式,这种方式也叫lowerCamel。 一个通用的做法是:所有的类型/ 类/函数名都用Pascal形式,所有的变量都用Camel形式。 类/类型/变量:名词或组合名词,如Member,PorductInfo等。 函数则用动词或动宾组合词来表示,如get/set、RenderPage()。
9.注释:注释是为了解释程序做什么(what),为什么这样做(why)。
需要特别注意的地方:复杂的注释应该放在函数头,很多函数头的注释都用来解释参数的类型等,如果程序正文已经能够说明参数的类型in/out,就不要重复! 注释也要随着程序的修改而不断更新。 注释(包括所有源代码)应该只用ASCII字符,不要用中文或者其他特殊字符,否则会极大地影响程序的可移植性。
-
代码设计规范相关规定:
1.函数:最重要的原则:只做一件事,并且要最好。
2.goto:函数最好有单一的出口,为达到这一目的,可以使用goto。只要有助于程序逻辑的清晰体现,什么方法都可以使用,包括goto。
3.错误处理:当程序的主要功能实现后,给代码加一些错误处理。
1) 参数处理:在debug版本中,所有的参数都要验证其正确性。在正式版本中,对从外部(用户或别的模块)传递过来的参数,要验证其正确性。 2) 断言:使用断言来验证正确性。
4.如何处理c++中的类:
注:处理关于异常的部分,大部分其他原则对C#也使用。 1)类: 使用类来封装面向对象的概念和多态( Polymorphism)。 避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要用类来实现。 对于有显式的构造和析构函数的类,不要建立全局的实体,因为你不知道它们在何时创建和消除。 仅在必要时,才使用“类”。 2)class vs.struct 如果只是数据的封装,用struct即可。 3)公共/保护/私有成员( public. protected和private ) 按照这样的次序来说明类中的成员: public、 protected. private。 4)数据成员 数据类型的成员用m_ name说明。 不要使用公共的数据成员,要用inline访问函数,这样可兼顾封装和效率。 5)虚函数 ( Virtual Function ) 使用虚函数来实现多态( Polymorphism)。 仅在很有必要时,才使用虚函数。 如果一个类型要实现多态,在基类( Base Class )中的析构函数应该是虚函数。 6)构造函数( Constructors ) 不要在构造函数中做复杂的操作,简单初始化所有数据成员即可。 构造函数不应该返回错误(事实上也无法返回)。把可能出错的操作放到HrInit()或FInit()中。 7)析构函数 ( Destructor ) 把所有的清理工作都放在析构函数中。如果有些资源在析构函数之前就释放了,记住要重置这些成员为0或NULL。 析构函数也不应该出错。 8)new 和delete 如果可能,实现自已的new/delete,这样可以方便地加上自已的跟踪和管理机制。自已的new/delete可以包装系统提供的new/delete. 检查new的返回值。new 不一定都成功。 释放指针时不用检查NULL。 9)运算符 ( Operators ) 在理想状态下,我们定义的类不需要自定义操作符。确有必要时,才会自定义操作符。 运算符不要做标准语义之外的任何动作。例如.“==”的判断不能改变被比较实体的状态。 运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。 当你拿不定主意的时候,用成员函数.不要用运算符。 10)异常( Exceptions ) 异常是在“异乎寻常”的情况下出现的,它的设置和处理都要花费“异乎寻常”的开销,所以不要用异常作为逻辑控制来处理程序的主要流程。 了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销。 当使用异常时,要注意在什么地方清理数据。 异常不能跨过DLL或进程的边界来传递信息,所以异常不是万能的。 11)类型继承( Class Inheritance ) 仅在必要时,才使用类型继承。 用const标注只读的参数(参数指向的数据是只读的,而不是参数本身)。 用const标注不改变数据的函数。
-
代码复审
1).代码复审的形式
名称 | 形式 | 目的 |
---|---|---|
自我复审 | 自己和自己 | 用同伴复审的标准来要求自己。不一定最有效,因为开发者对自己总是过于自信。如果能持之以恒,则对个人有很大好处。 |
同伴复审 | 复审者和开发者 | 简便易行 |
团队复审 | 团队和开发者 | 有比较严格的规定和流程,适用于关键的代码,以及复审后不再更新的代码。覆盖率高——有很多双眼睛盯着程序,但效率可能不高(全体人员都要到会)。 |
2).代码复审的步骤:
在复审前——
1.代码必须成功地编译, 在所有要求的平台上,同时要编译Debug | Retail版本。编译要用团队规定的最严格的编译警告等级(例如C/C++中的W4)。
2.程序员必须测试过代码。什么叫测试过?最好的方法是在调试器中单步执行。
3.程序员必须提供新的代码, 以及文件差异分析工具。用Windif或VSTS自带的工具都可以。VSTS中可以通过Shelveset 来支持远程代码复审。在复审中,复审者可以选择面对面的复审、独立复审或其他方式。
4.在面对面的复审中,一般是开发者控制流程,讲述修改的前因后果。但是复审者有权在任何时候打断叙述,提出自己的意见。
5.复审者必须逐一提供反馈意见。注意,复审者有权提出很多看似吹毛求疵的问题,复审者不必亲自调查每一件事,开发者有义务给出详尽的回答。
6.开发者必须 负责让所有的问题都得到满意的解释或解答,或者在TFS中创建新的工作项以确保这些问题会得到处理。
7. 对于复审的结果,双方必须达成一致的意见。
1)打回去——复审发现致命问题,这些问题在解决之前不能签人代码;
2)有条件地同意一发现了一些小问题,在这些问题得到解决或记录之后,代码可以签人,不需要再次复审;
3)放行——代码可以不加新的改动,签人源码控制服务器。
3).代码复审的目的在于:
1、找出代码的错误,比如:
1)编码错误,比如一些碰巧骗过了编译器的错误
2)不符合团队代码规范的地方
2、发现逻辑错误, 程序可以编译通过,但是代码的逻辑是错的
3、发现算法错误, 比如使用的算法不够优化,边界条件没有处理好等
4、发现潜在的错误 和回归性错误——当前的修改导致以前修复的缺陷又重新出现
5、发现可能需要改进的地方
6、教育(互相教育)开发人员,传授经验,让更多的成员熟悉项目各部分的代码,同时熟悉和应用领域相关的实际知识
-
结对编程概念:
是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。 输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员)。两个程序员经常互换角色。 和现实生活中的例子类似,一个人负责具体的执行(驾驶,用键盘编写程序等),另一人负责导航、检查、掩护等。 驾驶员( Driver) :控制键盘输人。 领航员( Navigator) :起到领航、提醒的作用。
任务2:两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价,具体要求如下:
(1)对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。
- 结对方博客链接:公海瑜
(2)克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
- 对方的项目源码未上传成功。
(3)依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。
任务3:采用两人结对编程方式,设计开发一款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)外的任意有效平台功能实现。
- 任务分析:
关于遗传算法:
通过查阅相关资料我了解到了遗传算法:
利用遗传算法求解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的组合)共八种情况。在同一时刻,每个项集的选择只能是八种情况之一。
遗传算法:基于随机的进化算法;希望通过多次将高质量的个体繁衍后,生出所需要的个体。随机:新的解会在原有的解上发生随机变化。
基本思想:遗传算法的搜索从一个被称作种群的候选解集开始,新的种群由旧的种群中产生以期得到更好的种群。从旧种群中按照解的适应度来选择解以产生新的解;适应度越大,解被选择生成后代的机率也越大。这个从已有种群中选择双亲并产生后代的迭代过程持续到遗传算法的停止条件满足为止。
遗传算法的基本元素:由染色体组成的种群,根据适应度进行选择以及交叉产生后代。
关键步骤如下:
(1)基因编码:在这个过程中,尝试对一些个体的基因做一个描述,构造这些基因的结构,有点像确定函数自变量的过程。
(2)设计初始群体:在这里需要造一个种群出来,这些种群有很多生物个体但基因不同。
(3)适应度计算:这里对那些不符合要求的后代进行剔除,不让他们产生后代。否则他们产生的后代只会让计算量更大而对逼近目标没有增益。
(4)产生下一代:有3种方法,即:直接选择,基因重组,基因突变
而后回到步骤(3)进行循环,适应度计算,产生下一代,这样一代一代找下去,直到找到最优解为止。
遗传算法流程图:
要采用遗传算法,则首先确定以下几个要素:染色体的编码方法、适值函数、染色体交叉和变异采用的方案、选择策略
与结对伙伴的交流学习:
本次项目的PSP展示:
PSP | 任务内容 | 计划共完成需要的时间(min) | 实际完成需要的时间(min) |
---|---|---|---|
Planning | 计划 | 8 | 30 |
Estimate | 估计这个任务需要多少时间,并规划大致工作步骤 | 8 | 30 |
Development | 开发 | 298 | --- |
Analysis | 需求分析 (包括学习新技术) | 20 | 30 |
Design Spec | 生成设计文档 | 15 | 25 |
Design Review | 设计复审 (和同事审核设计文档) | 10 | 20 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 3 | 5 |
Design | 具体设计 | 35 | --- |
Coding | 具体编码 | 155 | --- |
Code Review | 代码复审 | 15 | --- |
Test | 测试(自我测试,修改代码,提交修改) | 45 | --- |
Reporting | 报告 | 9 | 11 |
Test Report | 测试报告 | 3 | --- |
Size Measuremen | 计算工作量 | 3 | 2 |
Postmortem & Process Improvement Plan | 事后总结 ,并提出过程改进计划 | 3 | 4 |
三、实验总结
对于此次结对编程实验,我有如下感受及体会:第一次接触结对编程,对于结对编程的整体感受总的来说是利大于弊的,即有1+1>2的效果。
我认为或许结对编程并不适用于简单的写代码的工作,结对编程更适用于解决一些方向性的问题,因为在编程时,每个人的思想不同可能用到的方法及语句也就不同,所以难免会产生分歧与不一致,但是,两个人的思想可能会碰撞出新的火花,有时候还可以找到更适合、更节省空间与时间的方法与算法。在结对编程中,双方的互动目的在于开启思路,避免单独编程时思维容易阻塞的情况,有时候一个人在写代码时,难免会陷入僵局出不来,而两个人合作缺可以解决不这个问题,有时候对方的一句话可以启发自己换一种思考方式,从而高效地解决问题。
总体来说,结对编程可以很大程度上提高编程效率,而且两人轮流编程,不会太过疲惫,因此十分适合敏捷开发。如果未来我们从事软件开发的工作,我们会十分乐于进行结对编程,因为这会极大的改善我们的编程体验,是编程不再那么枯燥,debug之路也不会那么恐怖。