201971010208-古丽妮尕尔 实验三 结对项目—《{0-1}KP 实例数据集算法实验平台》项目报告

项目内容
课程班级博客链接 2019级卓越工程师班
这个作业要求链接 实验三 软件工程结对项目
我的课程学习目标
  • 体验软件项目开发中的两人合作,练习结对编程(Pair programming)
  • 掌握Github发布软件项目的操作方法
这个作业在哪些方面帮助我实现学习目标
  • 实践学习与他人合作,练习结对编程,认识代码规范的重要性
  • 掌握Github发布软件项目的操作方法
项目Github的仓库链接地址 仓库链接
结对方学号姓名 201971010145_姚恪
结对方本次博客作业链接 结对方作业链接

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

  • 代码风格规范

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

    • 概念:代码设计规范不光是程序书写的格式问题,而且涉及到程序设计、模块之间的关系、设计模式等方方面面,又有不少内容与具体程序设计语言息息相关(如C,C++,JAVA,C#),但是也有通用的原则。
    • 函数:原则:只做一件事,并且要做好。
    • goto:函数最好有单一出口,为了达到这一目的,可以使用goto。
    • 错误处理(参数处理):在Debug版本中,所有参数都要验证其正确性。
    • 错误处理(断言):检验正确性时,可以使用断言。
    • 类:
      1.使用类来封装面向对象的概念和多态。
      2.避免传递类型实体的值,应该用指针传递。换句话说,对于简单的数据类型,没有必要要用类来实现。
      3.对于有显示的构造和析构的类,不要建立全局的实体,因为不知道它们在何时创建和消除。
      4.仅在有必要时,才是用“类”。
    • class vs. struct:如果只是数据的封装,用struct即可。
    • 公共/保护/私有成员:按照这样的次序来说明类中的成员。
    • 数据成员:
      1.数据类型的成员用m_name说明。
      2.不要使用公共的数据成员,要用inline访问函数,这样才可兼顾封装和效率。
    • 虚函数:
      1.实现多态。
      2.仅在很有必要时,使用虚函数。
      3.若一类型实现多态,在基类中的析构函数应该是虚函数。
    • 构造函数:
      1.不做复杂操作。
      2.不应返回错误。
    • new 和 delete:
      1.尽量实现自己的new/delete。
      2.检查new的返回值。
      3.释放指针时不用检查NULL。
    • 运算符:
      1.无需自定义操作符。
      2.不要做标准语义之外的动作。
      3.运算符的实现必须非常有效率。
      4.当打不定主意时,用成员函数。
    • 异常:
      1.不要将异常作为处理程序主要流程。
      2.了解异常及处理异常的花销。
      3.使用时,注意在什么地方清理数据。
      4.异常不能跨过DLL或进程的边界来传递信息。
    • 类型继承:
      1.仅在必要时使用。
      2.用const标注只读的参数。
      3.用const标注不改变数据的函数。
  • 代码复审

    • 定义:看代码是否在代码规范的框架正确地解决了问题。
    • 形式:自我复审、同伴复审、团队复审。
  • 结对编程概念

    • 结对编程能提供更好的设计质量和代码质量,两人合作解决问题的能力更强。
    • 结对工作,信心大增,高质量的产出带来高满足感。
    • 结对能更有效的交流,相互学习传递经验,分享知识,应对人员流动。

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

结对对象 项目 仓库
姚恪—201971010145 实验二 姚恪仓库
  • 成果评价
评价项目 评价内容
博文结构 页面简介整齐,要素齐全且一目了然。
博文内容 最大程度达到了作业要求,极少部分地方出现了文字不对齐、序号重复等形式错误,内容饱满且完整
博文结构与PSP中“任务内容”列的关系 博文结构与“内容任务”列几乎一一对应,思路清晰
PSP数据的差异化分析与原因探究 具体完成时间与计划完成时间相差无几,因为本身具有扎实的代码功底以及规划能力,即使个别项目所用时间超出计划部分也没有因此拖整体进度。
  • 克隆结对方项目源码到本地机器,阅读并测试运行代码,参照《现代软件工程—构建之法》4.4.3节核查表复审同伴项目代码并记录。

    • 克隆对方项目
    • 测试代码


  • 代码审查

概要部分 执行情况
代码符合需求和规格说明么? 符合
代码设计是否考虑周全?
代码可读性如何? 符合代码规范,注释简单易懂
代码容易维护么? 容易
代码的每一行都执行并检查过了吗? 检查过了
设计规范部分
设计是否遵从已知的设计模式或项目中常用的模式? 遵从
有没有硬编码或字符串/数字等存在 不存在
代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64)? 不影响
在本项目中是否存在类似的功能可以调用而不用全部重新实现?
有没有无用的代码可以清除?
代码规范部分
修改的部分符合代码标准和风格吗? 符合
具体代码部分
有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常? 没有对错误进行预处理
参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度是以0开始计数还是以1开始计数?
边界条件是如何处理的? switch语句的default分支是如何处理的?循环有没有可能出现死循环? 没有使用switch语句所以循环不会出现死循环。
有没有使用断言( Assert)来保证我们认为不变的条件真的得到满足? 没有使用断言
数据结构中有没有用不到的元素? 看不出来
效能
代码的效能(Performance)如何?最坏的情况是怎样的? 运行效率高,没有遇到最坏的情况
代码中,特别是循环中是否有明显可优化的部分?
对于系统和网络的调用是否会超时?如何处理? 没有进行网络调用
可读性
代码可读性如何?有没有足够的注释? 注释简洁明了,符合规范
可测试性
代码是否需要更新或创建新的单元测试?
  • 结对方项目仓库中的Fork、Clone、Push、Pull request、Merge pull request日志数据

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

  • 需求分析
    • 平台基础功能:实验二 任务3;
    • {0-1}KP 实例数据集需存储在数据库;
    • 平台可动态嵌入任何一个有效的{0-1}KP 实例求解算法,并保存算法实验日志数据;
    • 人机交互界面要求为GUI界面(WEB页面、APP页面都可);
    • 查阅资料,设计遗传算法求解{0-1}KP,并利用此算法测试要求(3);
    • 附加功能:除(1)-(5)外的任意有效平台功能实现。
  • 软件设计说明
    • 将实验二的代码进行了扩充,套装了一个django框架
    • 但是仅仅能够实现数据的前端展示,是一个假的前端,没有完全实现前端功能
    • 使用python中django库中自带的sqlite数据库进行数据的传输
    • 功能流程图
graph LR start[算法平台] --> input[选择一个指定的背包数据] input --> conditionA[显示背包数据] conditionA --> conditionB[遗传算法] conditionA --> conditionC[动态规划] conditionA --> conditionD[贪心算法] conditionA --> conditionE[回溯法] conditionB --> printa[散点图] conditionC --> printa[散点图] conditionD --> printa[散点图] conditionE --> printa[散点图] printa --> stop[结束]
  • 核心代码展示
    • 遗传算法
      遗传算法通常实现方式为一种计算机模拟。对于一个最优化问题,一定数量的候选解(称为个体)可抽象表示为染色体,使种群向更好的解进化。传统上,解用二进制表示(即0和1的串),但也可以用其他表示方法。进化从完全随机个体的种群开始,之后一代一代发生。在每一代中评价整个种群的适应度,从当前种群中随机地选择多个个体(基于它们的适应度),通过自然选择和突变产生新的生命种群,该种群在算法的下一次迭代中成为当前种群。
点击查看代码
  ##初始化,N为种群规模,n为染色体长度
  def init(self,N,n):
      C = []
      for i in range(N):
          c = []
          for j in range(n):
              a = np.random.randint(0,2)
              c.append(a)
          C.append(c)
      return C


  ##评估函数
  # x(i)取值为1表示被选中,取值为0表示未被选中
  # w(i)表示各个分量的重量,v(i)表示各个分量的价值,w表示最大承受重量
  def fitness(self,C,N,n,W,V,w):
      S = []##用于存储被选中的下标
      F = []## 用于存放当前该个体的最大价值
      for i in range(N):
          s = []
          h = 0  # 重量
          f = 0  # 价值
          for j in range(n):
              if C[i][j]==1:
                  if h+W[j]<=w:
                      h=h+W[j]
                      f = f+V[j]
                      s.append(j)
          S.append(s)
          F.append(f)
      return S,F

  ## 适应值函数,B位返回的种族的基因下标,y为返回的最大值
  def best_x(self,F,S,N):
      y = 0
      x = 0
      B = [0]*N
      for i in range(N):
          if y<F[i]:
              x = i
          y = F[x]
          B = S[x]
      return B,y

  ## 计算比率
  def rate(self,x):
      p = [0] * len(x)
      s = 0
      for i in x:
          s += i
      for i in range(len(x)):
          p[i] = x[i] / s
      return p

  ## 选择
  def chose(self,p, X, m, n):
      X1 = X
      r = np.random.rand(m)
      for i in range(m):
          k = 0
          for j in range(n):
              k = k + p[j]
              if r[i] <= k:
                  X1[i] = X[j]
                  break
      return X1

  ## 交配
  def match(self,X, m, n, p):
      r = np.random.rand(m)
      k = [0] * m
      for i in range(m):
          if r[i] < p:
              k[i] = 1
      u = v = 0
      k[0] = k[0] = 0
      for i in range(m):
          if k[i]:
              if k[u] == 0:
                  u = i
              elif k[v] == 0:
                  v = i
          if k[u] and k[v]:
              # print(u,v)
              q = np.random.randint(n - 1)
              # print(q)
              for i in range(q + 1, n):
                  X[u][i], X[v][i] = X[v][i], X[u][i]
              k[u] = 0
              k[v] = 0
      return X

  ## 变异
  def vari(self,X, m, n, p):
      for i in range(m):
         for j in range(n):
              q = np.random.rand()
              if q < p:
                  X[i][j] = np.random.randint(0,2)
  	return X

  • 使用diango框架和构造数据库
点击查看代码
def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ex3.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()
 DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

  • 程序运行结果

  • 操作后记录

  • 结对沟通过程

  • 本次作业PSP

PSP 任务内容 计划共完成需要的时间(min) 实际完成需要的时间(min)
Planning 计划 30 30
Estimate 估计这个任务需要多少时间,并规划大致工作步骤 20 20
Development 开发 1200 1200+
Analysis 需求分析 (包括学习新技术) 120 150
Design Spec 生成设计文档 20 20
Design Review 设计复审 (和同事审核设计文档) 20 15
Coding Standard 代码规范 (为目前的开发制定合适的规范) 20 15
Design 具体设计 60 60
Coding 具体编码 600 650
Code Review 代码复审 30 30
Test 测试(自我测试,修改代码,提交修改) 200 260
Reporting 报告 100 100
Test Report 测试报告 30 40
Size Measurement 计算工作量 40 50
Postmortem & Process Improvement Plan 事后总结 ,并提出过程改进计划 20 30
  • 小结感受
    • 通过本次结对项目,感受到两个人互相督促去完成比一个人效率高,内容完成度更高。
    • 可以看到自己的不足之处,为了不拖后腿会去学习,而不是逃避。
    • 会拥有更多的视角解决问题。
posted @ 2022-04-04 17:42  Echo&  阅读(63)  评论(2编辑  收藏  举报