201871010014-陈园园 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告
| 项目 | 内容 |
| ---- | ---- | ---- |
| 课程班级博客链接 | 班级博客 |
| 这个作业要求链接 | 作业要求 |
| 我的课程学习目标 | (1)体验并感受两人合作,结对编程完成软件项目的开发。(2)练习Github协作开发程序的操作方法和过程。 |
| 这个作业在哪些方面帮助我实现学习目标 | (1)学习效率方面。两人合作结对编程的方式,提高了学习效率。(2)学习能力方面。一个人可能会学的很快,但两人人合作会使学习能力加强。(3)学习经验方面。相互学习可以取长补短,积累知识,增加学习经验。(4)学习内容方面。双方讨论学习可以深入探讨知识,学习内容更加充实。 |
| 结对方学号-姓名 | 201871010105—曹玉中 |
| 结对方本次博客作业链接 | 结对方博客作业链接 |
| 本项目Github的仓库链接地址 | 仓库链接 |
博客正文
任务1:
阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;
第3章基本内容:
(1) 个人能力的衡量与发展:软件工程包括了开发、运用、维护软件的过程中的很多技术、做法、习惯和思想。软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”,软件开发流程的目的是为了提高软件开发、运营和维护的效率,以及提升用户满意度、软件的可靠性和可维护性。
(2)初级软件工程师的成长包括以下几种:
a.积累软件开发相关的知识,提升技术技能(如对具体技术的掌握,动手能力)。例如:对JAVA、C/C++、C#的掌握,诊断/提高效能的技术,对于某一开发平台的掌握等。
b.积累问题领域的知识和经验。
c.对通用的软件设计思想和软件工程思想的理解。
d.提升职业技能,包括:自我管理的能力、表达交流的能力、与人合作的能力等。
e.实际成果——最重要的评价标准。
(3)软件工程师的职业发展:[软件工程师自我评价能力表](https://www.cnblogs.com/xinz/p/3852177.html)
第4章基本内容:
| 名词 | 内容 |
| ---- | ---- | ---- |
| 代码风格规范 | 主要是文字上的规定。(1)代码风格的原则是:简明、易读、无二义性;(2)对于缩进、行宽、括号、分行、命名、下划线、注释、大小写以及断行与空白的{}行的处理;(3)缩进限定为100字符;(4)复杂的条件表达式中,用括号表示逻辑优先级;(5)有清晰的断行和分行;命名应该遵循规则,简洁易懂。 |
| 代码设计规范 | (1)牵扯到程序设计、模块之间的关系、设计模式等。(2)针对函数:只做一件事,并且要做好。可以使用goto实现单一的出口;(3)还有错误处理方面的一些内容,比如断言的正确使用等规范;(4)错误处理的时间更甚于程序功能的实现;(5)所有的参数都要验证其正确性,验证正确性使用断言。 |
| 代码复审 | (1)形式:自我复审、同伴复审、团队复审;(2)目的:找出代码错误、发现逻辑错误、发现算法错误、发现潜在的错误和回归性错误、发现可能需要改进的地方、传授经验;(3)代码复审后把记录整理出来:更正明显的错误、记录无法很快更正的错误、把所有的错误记在自己的一个“我常犯的错误”表中,作为以后自我复审的第一步。 |
| 结对编程概念 | 角色:驾驶员:控制键盘输入;领航员:起到领航、提醒的作用。好处:(1)在开发层次,可以提供更好的设计质量和代码质量,两人合作解决问题的能力更强。(2)对开发人员,带来更多的信心,高质量的产出带来更高的满足感。(3)企业管理层次上,有效地交流,相互学习和传递经验,分享知识,取得更高的投入产出比。 |
任务2:
两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价,具体要求如下:
(1)对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。
(2)克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。
概要部分
- 代码能符合需求和规格说明么?答:能符合需求与规格。
- 代码设计是否有周全的考虑? 答:不太周全,修改了很多次,刚开始可能设计部分有一些问题。
- 代码可读性如何? 答:简单易懂。
- 代码容易维护么? 答:比较容易。
- 代码的每一行都执行并检查过了吗? 答:是的,检查过。
设计规范部分
- 设计是否遵从已知的设计模式或项目中常用的模式? 答:是。
- 代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64) 答:没有依赖,不会影响。
- 开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现? 答:可以实现,不存在。
- 有没有无用的代码可以清除?(很多人想保留尽可能多的代码,因为以后可能会用上,这样导致程序文件中有很多注释掉的代码,这些代码都可以删除,因为源代码控制已经保存了原来的老代码。) 答:有,已清除。
代码规范部分
- 修改的部分符合代码标准和风格么(详细条文略)? 答:符合代码标准。
具体代码部分
- 有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常? 答:查阅资料并讨论以后发现基本没有。
- 参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数? 答:基本无错误,字符串的长度是字节的长度,以0开始计数。
- 边界条件是如何处理的?Switch语句的Default是如何处理的?循环有没有可能出现死循环? 答:通过检查代码和讨论,循环不会出现死循环。
-有没有使用断言(Assert)来保证我们认为不变的条件真的满足? 答:没有使用。
- 对资源的利用,是在哪里申请,在哪里释放的?有没有可能导致资源泄露(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有可能优化? 答:因为没有上线使用,基本不会导致资源泄露,没有优化。
- 数据结构中是否有无用的元素? 答:检查过后没有。
(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)外的任意有效平台功能实现。
设计前期知识:
遗传算法:
- 遗传算法是根据生物进化的模型提出的一管优化算法。
- 原理:遗传算法将生物进化原理引入待优化参数形成的编码串群体中,按着一定的适值函数及一系列遗传操作对各个体进行筛选,从而使适值高的个体被保留下来,组成新的群体,新群体包含上一代的大量信息,并且引入了新的优于上一代的个体。这样周而复始,群体中各个体适值不断提高,直至满足一定的极限条件。此时,群体中适值最高的个体即为待优化参数的最优解。
- 特点:
(1)遗传算法是对参数的编码进行操作,而非对参数本身。
(2)遗传算法是从许多点开始并行操作,并非局限于一点,从而可有效防止搜索过程收敛于局部最优解。
(3)遗传算法通过目标函数计算适值,并不需要其它推导和附加信息,因而对问题的依赖性较小。
(4)遗传算法的寻优规则是由概率决定的,而非确定性的。
(5)遗传算法在解空间进行高效启发式搜索,而非盲目地穷举或完全随机搜索。
(6)遗传算法对所求解的优化问题没有太多的数学要求。
(7)遗传算法具有并行计算的特点,因而可通过大规模并行计算来提高计算速度。 - 基本操作:遗传、变异和交叉。
- 1、需求分析:遗传算法作为当今一个比较热门的研究方向,在解决最优化问题上有着良好的作用。遗传算法利用基因编码,对其进行生成、杂交、变异、选择等操作,产生不同的基因序列,使解一步一步向最优解逼近,未来发展前景也是相当不错的。
- 2、设计实现:
代码片段:
/*
初始化种群
*/
public void init(){
for(int i=0;i<charge.length;i++){
density[i]=charge[i]/weight[i];
}
for(int i=0;i<popSize;i++){
Chromosome g=new Chromosome(50);
changeGene(g);
population.add(g);
}
caculteFitness();
}
/*
计算种群适应度
*/
public void caculteFitness(){
bestFitness=population.get(0).getFitness();
worstFitness=population.get(0).getFitness();
totalFitness=0;
for (Chromosome g:population) {
//changeGene(g);
setNowGenome(g);
if(g.getFitness()>bestFitness){
setBestFitness(g.getFitness());
if(y<bestFitness){
y=g.getFitness();
}
setIterBestFit(g);
}
if(g.getFitness()<worstFitness){
worstFitness=g.getFitness();
}
totalFitness+=g.getFitness();
}
averageFitness = totalFitness / popSize;
//因为精度问题导致的平均值大于最好值,将平均值设置成最好值
averageFitness = averageFitness > bestFitness ? bestFitness : averageFitness;
}
/*
进化算法
*/
public void evolve() {
List<Chromosome> childrenGenome = new ArrayList<Chromosome>();
for (int j = 0; j < popSize / 2; j++) {
Chromosome g1 = getChromoRoulette();
Chromosome g2 = getChromoRoulette();
double r = random.nextDouble();
if (r <= crossoverRate) {
List<Chromosome> children = genetic(g1, g2);
if (children != null) {
for (Chromosome g : children) {
changeGene(g);
childrenGenome.add(g);
g.mutation(50, mutationRate);
changeGene(g);
childrenGenome.add(g);
}
}
}
childrenGenome.add(g1);
childrenGenome.add(g2);
}
List<Chromosome> temGen = new ArrayList<Chromosome>();
population.clear();
for (int i = 0; i < popSize*0.2; i++) {
int max = 0;
for (Chromosome tempG : childrenGenome) {
if (tempG.getFitness() > max) {
max = tempG.getFitness();
setBestFit(tempG);
}
}
temGen.add(getBestFit());
childrenGenome.remove(getBestFit());
setBestFit(null);
}
population = childrenGenome;
caculteFitness();
while (temGen.size() < popSize) {
Chromosome tp1 = getChromoRoulette();
temGen.add(tp1);
}
/*
while (temGen.size()<popSize){
Chromosome tp1=new Chromosome(50);
temGen.add(tp1);
}
*/
population = temGen;
//重新计算种群适应度
caculteFitness();
}
/*
遗传算法GA流程
*/
public void geneticAlgorithProcess(){
generation=1;
init();
while(generation<iterNum){
evolve();
print();
generation++;
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("doGet is called========");
response.setContentType("text/html");
PrintWriter out = response.getWriter();//获得输出流对象
String name=request.getParameter("username");
String pass=request.getParameter("password");
if(name.equals("xyz")&&pass.equals("123")){
out.println(" login success!");//用输出流,向客户端输出响应
System.out.println("login success!");//服务器端控制台输出
}
else{
out.println(" login failed!");//用输出流,向客户端输出响应
System.out.println("login failed!");//服务器端控制台输出
}
}
-
3、程序运行:
-
4、结对的过程:
-
5、结对编程PSP:
任务内容 | 计划共完成需要的时间(min) | 实际完成需要的时间(min) |
---|---|---|
计划 | 40 | 30-40 |
· 估计这个任务需要多少时间,并规划大致工作步骤 | 25 | 20-30 |
开发 | 900 | 1000 |
需求分析 (包括学习新技术) | 30-40 | 35 |
· 生成设计文档 | 25 | 30 |
· 设计复审 (和同事审核设计文档) | 120 | 130 |
代码规范 (为目前的开发制定合适的规范) | 100 | 100 |
具体设计 | 200-300 | 150 |
具体编码 | 680-800 | 900 |
· 代码复审 | 100 | 110 |
· 测试(自我测试,修改代码,提交修改) | 70 | 90 |
报告 | 80 | 60 |
· 测试报告 | 30 | 30 |
计算工作量 | 40 | 30-50 |
· 测试报告 | 25 | 10-20 |
· 事后总结 ,并提出过程改进计划 | 15 | 15 |
- 7、小结感受
通过这次实验的结对编程,我觉得两人合作真的能够带来1+1>2的效果。首先,在软件开发的过程中,结对编程可以提高软件开发效率的;其次,它还可以减少软件中的错误与漏洞。另外,在测试过程中,我和结对伙伴可以分饰两角:软件工程师和客户,可以更好的去改进项目,提高软件项目的人机交互体验。但是,由于我们编程能力都不好,所以,任务完成得不是很好。