201971010115-蒋敏敏 实验三 结对项目—《{0-1}KP 实例数据集算法实验平台》项目报告

项目 内容
课程班级博客链接 2019级卓越工程师班
这个作业要求链接 实验三 软件工程结对项目
我的课程学习目标

(1) 体验软件项目开发中的两人合作,练习结对编程

(2) 掌握Github协作开发软件的操作方法。

(3) 阅读《构建之法》

学习一些技术方法和软件开发工具的使用

这个作业在哪些方面帮助我实现学习目标

(1) 通过0/1背包问题,学会了两人合作开发项目

(2) 掌握Github协作开发软件的操作方法

(3) 将之前学过的东西综合化,运用于实际

(4) 逐渐熟悉软件项目开发流程

结对方学号-姓名 201971010231-毛玉贤
结对方本次博客作业链接 201971010231-毛玉贤 实验三 结对项目—《{0-1}KP 实例数据集算法实验平台》项目报告
项目Github的仓库链接地址 仓库地址

任务1:阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念;

1. 代码风格规范:主要是代码书写格式规范,其原则是:简明、易读、无二义性。主要包含以下内容:

项目 内容
缩进 可以使用Tab键以及2、4、8等空格。个人认为依据不同是编程语言,可以使用不同的缩进方式。
行宽 对行宽进行同一设置。
括号 用括号清楚的表明逻辑优先级。
断行与空白的{}行 主要是在多层循环中规范使用。
分行 不要把多条语句放在一行上。
命名 命名能够表明变量的类型及相应的语义,简洁易懂。
下划线 合理使用来分隔变量名字中的作用域标注和变量的语义。
大小写 多个单次组成的变量名,用大小写区分,例如著名的驼峰式命名法。
注释 能够很好的解释程序是做什么的,以及为什么这样做。

2. 代码设计规范: 不光是程序书写的问题,而且牵涉到程序设计、模块之间的关系、设计模式等的方方面面包含以下部分:

项目 内容
goto 函数最好有单一的出口,可以使用goto。
函数 能够很好的完成一件事。
c++类的处理 注意类、classvc.struct、公共/保护/私有成员、数据成员、虚函数、构造函数、析构函数、new和delete、运算符、异常处理、类型继承等的规范设计。
错误处理 预留足够的时间,使用的方法包括参数处理和断言。
断言 使用断言来验证正确性。
参数处理 在debug版本中,所有的参数都要验证其正确性。在正式版本中,对从外部(用户或别的模块)传递过来的参数,要验证其正确性。
数据成员 数据类型的成员用m_ name说明。不要使用公共的数据成员,要用inline访问函数,这样可兼顾封装和效率。
构造函数 不要在构造函数中做复杂的操作,简单初始化所有数据成员即可。构造函数不应该返回错误(事实上也无法返回)。把可能出错的操作放到HrInit()或FInit()中。
异常 异常是在“异乎寻常”的情况下出现的,它的设置和处理都要花费“异乎寻常”的开销,所以不要用异常作为逻辑控制来处理程序的主要流程。了解异常及处理异常的花销,在C++语言中,这是不可忽视的开销。当使用异常时,要注意在什么地方清理数据。异常不能跨过DLL或进程的边界来传递信息,所以异常不是万能的。
运算符 在理想状态下,我们定义的类不需要自定义操作符。确有必要时,才会自定义操作符。运算符不要做标准语义之外的任何动作。运算符的实现必须非常有效率,如果有复杂的操作,应定义一个单独的函数。当你拿不定主意的时候,用成员函数,不要用运算符。

3. 代码复审:看代码是否在代码规范的框架内正确地解决了问题。代码复审的三种形式:自我复审、同伴复审、团队复审。

  • 自我复审:用同伴复审的标准来要求自己。不一定最有效, 因为开发者对自己总是过于自信。如果能持之以恒,则对个人有很大好处。
  • 同伴复审:简单易行。
  • 团队复审:有比较严格的规定和流程,适用于关键的代码,以及复审后不再更新的代码。覆盖率高——有很多双眼睛盯着程序,但效率可能不高。

4. 结对编程:指一起分析,一起设计,一起写测试用例,一起做单元测试,一起做集成测试,一起写文档等等。

  • 角色:驾驶员:控制键盘输入;领航员:起到领航、提醒的作用。
  • 好处:在开发层次,可以提供更好的设计质量和代码质量,两人合作解决问题的能力更强;对开发人员,带来更多的信心,高质量的产出带来更高的满足感;企业管理层次上,有效地交流,相互学习和传递经验,分享知识,取得更高的投入产出比。
  • 目的:每人在各自独立设计、实现软件的过程中不免要犯这样那样的错误。在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。

任务2:两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价,具体要求如下:

(1)对项目博文作业进行阅读并进行评论,评论要点包括:博文结构、博文内容、博文结构与PSP中“任务内容”列的关系、PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究,将以上评论内容发布到博客评论区。

项目 内容
结对方 201971010231-毛玉贤
结对方实验二博客链接 201971010231-毛玉贤 实验二 个人项目—《KP问题》项目报告
结对方实验二Github项目仓库链接 仓库地址
评价内容

(1)博文结构:博文整体排版较好,清晰易读,字体大小适中博文可读性强。

(2)博文内容:实验内容完成度不错,对需求分析、功能设计及设计实现设计实现都进行了详细的陈述,但是没有完成扩展部分,还有就是模块化编程这方面实现不是很好,建议将代码写成多个文件放在一个项目下会增加可读性,也便于修改。

(3)博文结构与PSP中“任务内容”列的关系:可以看出博文整体结构基本对应了PSP中的“任务内容”,在进行计划分析后,也得出了需求分析,生产设计文档,有自己的编码规范风格,有具体的设计,以及编码、测试、修改代码(完善功能)、提交代码、提交博文、事后总结等过程。

(4)PSP中“计划共完成需要的时间”与“实际完成需要的时间”两列数据的差异化分析与原因探究上:在代码复审阶段,博主实际完成的时间与计划完成的时间差距较大,时间少了一半,可见在第一次编写代码时完成度比较高,基本都已实现。

(2)克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。

  • 克隆项目

  • 阅读测试

  • 核查表复审

项目 内容 实际完成情况
概要部分 1)代码符合需求和规格说明么? 较符合
2)代码设计是否考虑周全? 考虑的较为周全
3)代码可读性如何? 代码的可读性较;
4)代码容易维护么? 较易维护
5)代码的每一行都执行并检查过了吗? 都已检查并执行
设计规范部分 1)设计是否遵从已知的设计模式或项目中常用的模式? 遵从
2)有没有硬编码或字符串/数字等存在? 没有
3)代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到 Win64 )? 没有,不会影响移植
4)开发者新写的代码能否用已有的 Library/SDK/Framework 中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现? 可以,部分代码可以调用
5)有没有无用的代码可以清除?
代码规范部分 1)修改的部分符合代码标准和风格么? 基本符合
具体代码部分 1)有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常? 对相关错误进行了处理,没有异常
2)参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以 0 开始计数还是以 1 开始计数? 以0开始
3)边界条件是如何处理的?switch语句的default分支是如何处理的?循环有没有可能出现死循环? 对switch语句的default分支进行了错误处理,没有出现死循环
4)有没有使用断言(Assert)来保证我们认为不变的条件真的得到满足? 没有
5)对资源的利用,是在哪里申请,在哪里释放的?有无可能存在资源泄漏(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有优化的空间? 对资源的利用,在最开始申请,在完成相关功能的计算后将其释放,没有资源泄露,没有优化空间
6)数据结构中有没有用不到的元素? 没有
效能 1)代码的效能(Performance)如何?最坏的情况是怎样的? 基本完成了具体任务要求
2)代码中,特别是循环中是否有明显可优化的部分(C++中反复创建类,C# 中 string 的操作是否能用 StringBuilder 来优化)? 没有
3)对于系统和网络的调用是否会超时?如何处理? 未出现超时现象
可读性 1)代码可读性如何?有没有足够的注释?
可测试性 1)代码是否需要更新或创建新的单元测试?针对特定领域的开发(如数据库、网页、多线程等),可以整理专门的核查表。 代码需要更新和创建新的单元测试。可以针对部分功能的实现对代码进行进一步改进或创建新的单元测试。

(3)依据复审结果尝试利用github的Fork、Clone、Push、Pull request、Merge pull request等操作对同伴个人项目仓库的源码进行合作修改。

  • 经过代码复审,发现原有算法复杂度较高,有些代码存在冗余,对其进行了算法优化和代码简化

  • fork记录

任务3:采用两人结对编程方式,设计开发一款{0-1}KP 实例数据集算法实验平台

1.项目背景

 {0-1}背包问题({0-1 }Knapsack Problem,{0-1}KP)是最基本的KP问题形式,它的一般描述为:从若干具有价值系数与重量系数的物品(或项)中,选择若干个装入一个具有载重限制的背包,如何选择才能使装入物品的重量系数之和在不超过背包载重前提下价值系数之和达到最大?

2.可行性分析

(1)技术可行性:本次项目平台实现用到了python语言与其GUI界面,用现有技术可以实现。
(2)经济可行性:本次设计用来锻炼自身能力,不用于市场,不涉及经济效益。
(3)操作可行性:平台具有友好的人机交互功能,方便用户操作。

3.需求分析

  • Who 为谁设计,用户是谁?

    • 0-1背包问题在现实中有着广泛的应用背景,如预算控制、项目选择、材料切割、货物装载等,用户是在相应的场景中需要拿到最优解的群体。
  • What 需要解决如下问题?

    • 导入数据
      • 从本地可选择{0-1}KP 实例数据文件数据导入数据库。
      • 平台可选取数据库里任意一组数据。
    • 算法求解
      • 能够自主选择贪心算法、动态规划算法、回溯算法和遗传算法求解指定{0-1} KP数据的最优解(或近似解)和求解时间(以秒为单位)。
    • 绘图
      • 能够绘制任意一组{0-1}KP数据以重量为横轴、价值为纵轴的散点图。
      • 能够绘制任意一组{0-1}KP数据以价值重量为横轴、背包编号为纵轴的柱状图。
    • 排序
      • 对任意一组{0-1}KP数据按重量比进行非递增排序。
      • 对任意一组{0-1}KP数据按重量比进行非递减排序。
    • 结果保存
      • 任意一组{0-1} KP数据的最优解、求解时间和解向量可保存为txt文件。
      • 对任意一组{0-1}KP数据绘制的图存入指定文件夹。
    • 界面
      • 通过python实现的GUI界面。
    • 日志
      • 可将每次使用平台的时间,操作,涉及的文件记录存入数据库。
    • 附加功能
      • 可从本地选择任意{0-1}KP 实例数据文件数据导入数据库。
      • 递增排序
      • 绘制柱状图
      • 将对任意一组{0-1}KP数据绘制的图(散点图和柱状图)存入指定的文件夹(picture)下面,图片名根据操作的文件名进行改变。
  • Why 为什么解决这些问题?

    • 加深对解决0-1背包问题的不同算法的理解,提高自身编程能力,学会完整的开发软件项目。

4.功能设计

5.设计实现

  • 1)系统流程图

  • 2)项目结构

  • main.py 为人机交互主界面

  • DP.py、backtrack.py、Greedy.py、heredity.py 分别是动态规划法、回溯法、贪心法、遗传算法。

  • draw_picture.py 绘制散点图和柱状图

  • sort.py 实现递增递减排序。

  • follow_root.py 人机交互子界面,例如算法,绘图,排序,日志等的操作显示。

  • selectfiles.py 选择要执行的操作。

  • datafile.db 数据库文件

  • search.py 主要是对数据库的操作。

  • 3)动态规划法:动态规划基本思想是通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

    • 先找出状态转移方程
    • 根据状态转移方程填表,最后填完的数字为整个问题的最优解。
  • 4)贪心算法:在每一步做出的选择都是当时看起来的最优选择,即局部最优选择。

    • 先将物品按单位价值递减排序。
    • 排序后依次装入直到装不进去。
  • 5)回溯算法:遍历解空间,从根结点出发,按照深度优先的策略进行搜索,对于解空间树的某个结点,如果该结点满足问题的约束条件,则进入该子树继续进行搜索,否则将以该结点为根结点的子树进行剪枝。
    用递归函数Backtrack (i,cp,cw)来实现回溯法搜索子集树(形式参数i表示递归深度,n用来控制递归深度,形式参数cp和cw表示当前总价值和总重量,bestp表示当前最优总价值):

    • 若i >n,则算法搜索到一个叶结点,判断当前总价值是否最优:若cp>bestp,更新当前最优总价值为当前总价值(即bestp=cp),更新
      装载方案(即bestx[i]=xi);
    • 采用for循环对物品i装与不装两种情况进行讨论(0≤j≤1):
      • x[i]=j;
      • 若总重量不大于背包容量(即cw+x[i]w[i]<=c),则更新当前总价值和总重量(即cw+=w[i]x[i],cp+=p[i]*x[i]), 对物品i+1调用递归函数Backtrack(i+1,cp,cw) 继续进行装载;
      • 函数Backtrack(i+1,cp,cw)调用结束后则返回当前总价值和总重量(即 cw-=w[i]x[i],cp-=p[i]x[i]);
      • 当j>1时,for循环结束;
    • 当i=1时,若已测试完所有装载方案,外层调用就全部结束;
  • 6)遗传算法:只是比漫无目的的穷举搜索算法聪明一点点,通过较小的计算量获得较大的收益。适合-非线性问题。人工智能、自适应控制、机器学习等领域。不依赖目标函数。z基于概率论,而不是一个确定的搜索过程,即每一次启发式搜索,可能会得出不同的最优解。可能得到局部最优解或近似最优解。
    遗传算法主要有以下几个步骤

    • 初始化种群 ——> 种群适应度计算 ——> 种群选择 ——> 种群交配 ——> 种群变异 ——> 第五步完成后又跳转到第二部迭代计算,直到达到收敛条件。
  • 7)函数调用关系
    主要函数功能:

    • openfile() :打开所选择的本地文件,显示其内容到平台界面上;
    • inSql() :将打开的文件内容保存到数据库中;
    • Dp()、Greedy()、Bt()、heredity() :分别实现动规、贪心、回溯、遗传算法,并将结果保存在本地txt文件中(在inmain()中被调用);
    • scatter()、barh():实现绘制散点图、柱状图功能,并保存结果到本地src文件夹下面的picture文件夹下(在inmain2()中被调用);
    • increase()、decrease() :分别实现数据按单位重量价值递增、递减排序(在inmain3()中被调用);
    • log():从数据库log表当中取出数据(在inmain4()中被调用)
    • in_log() :将得到的日志记录数据存入数据库log表当中(在各个具体实现功能的函数中被调用);
    • inmain() :用来判断选择、执行四大算法,并将最终结果显示到平台上;
    • inmain2() :选择、执行绘图功能,并将所绘制的图像显示到界面上;
    • inmain3() :选择、执行排序功能,并将所绘制的图像显示到平台上;
    • inmain4() :获取数据库日志表当中的数据,显示日志记录;

6.主要代码

从本地选取文件数据并显示
# 打开文件
def openfile():
    filePath = askopenfilename()  # 全路径
    fileName = os.path.basename(filePath)  # 文件名
    tab = Frame(master=tabBar)
    tabBar.add(tab, text=fileName)
    textContainer = Labelframe(tab)
    textContainer.pack(expand=YES, fill=BOTH)
    tabBar.pack(expand=YES, fill=BOTH)
    textArea = Text(master=textContainer)
    textArea.pack(side=LEFT, expand=YES, fill=BOTH)
    inSql(filePath, fileName, textArea)
    time1 = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) # 执行该操作的时间
    in_log(time1, '导入数据', fileName)
    # 右侧滑动条
    scrollBar = Scrollbar(master=textContainer)
    scrollBar.pack(side=RIGHT, fill=Y)
    # 导航条获得文本位置
    scrollBar.config(command=textArea.yview)
    # 文本获得导航条位置
    textArea.config(yscrollcommand=scrollBar.set)
文件数据存入数据库
# 写入数据库
def inSql(filePath, fileName, textArea):
    cx = sqlite3.connect('./datafile.db')  # 创建数据库,如果数据库已经存在,则链接数据库;如果数据库不存在,则先创建数据库,再链接该数据库。
    cu = cx.cursor()  # 定义一个游标,以便获得查询对象。
    cu.execute('create table if not exists ' + "'" + fileName + "'" + ' (id integer primary key,w integer,v integer )')  # 创建表,此处须修改表名
    f = open(filePath, mode='r', encoding="utf-8")
    list = []
    i = 0
    for line in f.readlines():
        textArea.insert(INSERT, line)
        list.append(line.strip().split(' '))
        cu.execute('insert into '+ "'" + fileName + "'" + ' values(?,?,?)', (i, list[i][0], list[i][1]))
        i += 1
    f.close()  # 关闭文件
    cu.close()  # 关闭游标
    cx.commit()  # 事务提交
    cx.close()  # 关闭数据库
动态规划法
def bag(n, c, w, v, s, last_time):
    # 置零,表示初始状态
    value = [[0 for j in range(c + 1)] for i in range(n + 1)]
    for i in range(1, n+1):
        for j in range(1, c+1):
            value[i][j] = value[i - 1][j]
            # 背包总容量够放当前物体,遍历前一个状态考虑是否置换
            if j >= w[i - 1] and value[i][j] < value[i - 1][j - w[i - 1]] + v[i - 1]:
                value[i][j] = value[i - 1][j - w[i - 1]] + v[i - 1]

    print("最大价值为:", value[i][j])
    maxvalue = value[i][j]
    file_handle = open('result.txt', mode='a')
    file_handle.write('动态规划法\n')
    file_handle.write(s)
    file_handle.write('  最大值:')
    file_handle.write(str(value[i][j]))
    j = c
    i = n
    y1 = [0 for i in range(1, n+1)]
    while i != 0:
        if value[i][j] > value[i-1][j]:
            y1[i-1] = 1
            j = j-w[i-1]
        else:
            y1[i-1] = 0
        i = i-1
回溯法
def backtrack(i, w, v, n, c, x):
    global bestV, curW, curV, bestX
    if i >= n:
        if bestV < curV:
            bestV = curV
            bestX = x[:]
    else:
        if curW+w[i] <= c:
            x[i] = 1
            curW += w[i]
            curV += v[i]
            backtrack(i+1, w, v, n, c, x)
            curW -= w[i]
            curV -= v[i]
        x[i] = 0
        backtrack(i+1, w, v, n, c, x)
贪心法
def Greedy(s):
    x = []
    y = []
    y1 = []
    last_time = time.time()
    c, n, w, v = search.table_data(s)
    print("背包容量:", c, "物品个数:", n)
    print("重量:", w)
    print("价值:", v)
    value = 0
    weight = 0
    vw(c, n, w, v, x, y, y1)
    for i in range(len(w)):
        if w[y[i]-1] + weight < c:
            value += v[y[i]-1]
            weight += w[y[i]-1]
            y1[y[i]-1] = 1
        else:
            y1[y[i]-1] = 0
遗传算法
def heredity(s):
    last_time = time.time()
    m = 8  # 规模
    N = 800  # 迭代次数
    Pc = 0.8  # 交配概率
    Pm = 0.05  # 变异概率
    w, n, W, V = table_data(s)

    C = init(m, n)
    S,F = fitness(C,m,n,W,V,w)
    B, y = best_x(F,S,m)
    Y = [y]
    for i in range(N):
        p = rate(F)
        C = chose(p, C, m, n)
        C = match(C, m, n, Pc)
        C = vari(C, m, n, Pm)
        S, F = fitness(C, m, n, W, V, w)
        B1, y1 = best_x(F, S, m)
        if y1 > y:
            y = y1
        Y.append(y)
查看日志记录
def log():
    mydb = sqlite3.connect('datafile.db')  # 链接数据库
    cur = mydb.cursor()  # 创建游标cur来执行SQL语句

    # 获取表名
    cur.execute('SELECT * FROM log')
    list = cur.fetchall()
    for i in range(len(list)):
        print(list[i])
    return list
绘制散点图
# 散点图
def scatter(s):
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    # matplotlib画图中中文显示会有问题,需要这两行设置默认字体

    plt.xlabel('重量')
    plt.ylabel('价值')
    plt.xlim(xmax=200, xmin=0)
    plt.ylim(ymax=150, ymin=0)
    c,n,w,v = table_data(s)
    colors = 'blue'  # 点的颜色
    area = np.pi * 3**2  # 点面积
    # for i in range(len(w)):
    plt.scatter(w, v, s=area, c=colors, alpha=0.1, label=' ')
    plt.legend()
    plt.yticks(())
    plt.title('散点图')
    plt.savefig('./src/picture/scatter_' + s + '.png')  # 保存图片
    plt.show()
绘制柱状图
# 柱状图
def barh(s):
    fig, ax = plt.subplots()
    c, n, w, v = table_data(s)
    y=[]
    print(w,v)
    for i in range(len(w)):
        y.append(v[i]/w[i])
    # print(y)
    y_pos = np.arange(len(w)) + 1
    ax.barh(y_pos, y, color='b', align="center")
    plt.savefig('./src/picture/' + s + '.png')  # 保存图片
    plt.show()

7.项目代码代码规范

项目
规则
缩进 (1)程序块要采用缩进风格编写,缩进的空格数为4个;
(2)缩进或者对齐只能使用空格键,不可使用TAB键,使用TAB键需要设置TAB键的空格数目是4格 ;
变量命名 (1)命名尽量使用英文单词,力求简单清楚;
(2)命名规范必须与所使用的系统风格保持一致,并在同一项目中统一;
(3)全小写或全大写(可加下划线);
每行最多字符数 (1)较长的语句(>100 字符)要分成多行书写 )要分成多行书写;
函数最大行数 (1)函数的规模尽量限制在100 行以内;
函数、类命名 (1)模块尽量使用小写命名,首字母保持小写,尽量不要用下划线;
(2)类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头;
(3)函数名一律小写,如有多个单词,用下划线隔开;
常量 (1)常量使用以下划线分隔的大写命名;
空行规则 (1)模块级函数和类定义之间空两行;
(2)类成员函数之间空一行;
空格规则 (1)关键字之后要留空格。 const、virtual、inline、case 等关键字之后至少要留一个空格;
(2)if、for、while 等关键字之后应留一个空格再跟左括号‘( ’, 以突出关键字;
(3)变量名后紧跟逗号,逗号后空格;
注释规则 (1)“#”号后空一格,段落间用空行分开(同样需要“#”号);
(2)不要在文档注释复制函数定义原型, 而是具体描述其具体内容, 解释具体参数和返回值等;
操作符前后空格 (1)在二元运算符两边各空一格 =, -, +=, ==, >, <, >=, <= 等等。

8.测试运行

主界面

导入数据

算法求解

动态规划法求解

贪心法求解

回溯法求解

遗传算法求解

求解结果存入

绘图

散点图

柱状图

排序

递增排序

递减排序

日志记录

  • 数据库中

  • 界面上

图片存入文件夹

9.两人合作讨论提交记录

  • 主要通过当面交流和企业微信两种方式
    采用汉堡包法实施项目结对中两个人的沟通:断言、桥梁、说服(部分截图)

  • 提交展示

10. PSP展示

PSP2.1 任务内容 计划设计完成需要时间(min) 实际需要时间
Planning 计划 25 30
Estimate 估计任务时间,规划工作步骤 19 21
Development 开发 1442 1481
Analysis 需求分析(包括学习新技术) 120 152
Design Spec 生成设计文档 18 15
Design Review 设计复审(和同事审核设计文档) 10 8
Coding Standard 代码规范 10 8
Design 具体设计 75 55
Coding 具体编码 1080 1102
Code Review 代码复审 30 30
Test 测试(自我测试、修改、提交) 35 30
Reporting 报告 90 70
Test Report 测试报告 10 10
Size Measurement 计算工作量 5 3
Postmortem & Process Improvement Plan 事后总结,提出过程改进计划 8 5

任务4:完成结对项目报告博文作业

  • 已完成并提交

项目总结

  • 我认为两人合作可以带来1+1>2的效果,但是有利也有弊。之前的项目大多都是自己一个人完成,完成的速度也比较快,但是有时候会遇到自己看不出来的问题,这时,可能其他人就可以看出问题出在哪里,这次项目中,两个人合作完成,因为要互相交流讨论,最后才做出决定,因此完成项目的时间会长点,但是学到的东西也挺多的,能学习到对方更简便灵活的解决方式,拓宽了自己的思维。总体来说,这次合作中,利大于弊,我更倾向于团队合作,在合作中提高自己的能力和专业素养。
posted @ 2022-04-04 19:16  欽衣  阅读(62)  评论(4编辑  收藏  举报