Loading

2022-北航敏捷软件工程-个人阅读作业-阅读和调研

项目 内容
这个作业属于哪个课程 2022 年北航敏捷软件工程
这个作业的要求在哪里 个人阅读作业-阅读和调研
我在这个课程的目标是 了解并体验软件工程,实现从「程序」到「软件」的进展。
这个作业在哪个具体方面帮助我实现目标 初步了解软件工程,加深对源代码版本管理软件的理解,强化对 CI/CD 的应用。

\[\text{软件} = \text{程序} + \text{软件工程} \]

——《构建之法》

和程序打了两年半交道,许多习惯几乎是和软件工程完全背道而驰,例如:

  • 样例过了就交,懒得测试。
  • 追求一发就过,认为调试浪费时间。
  • 代码写完就扔,越短越好,疯狂压行。

希望可以通过本学期的课程,体验软件工程,养成更好的习惯,在实践中实现从「程序」到「软件」的进展。

阅读提问

问题一:单元测试为什么必须由程序的作者来写?

单元测试必须由最熟悉代码的人(程序的作者)来写。

代码的作者最了解代码的目的、特点和实现的局限性。所以,写单元测试没有比作者更适合的人选了。

——《构建之法》第 2 章 2.1.2 好的单元测试标准

我认为单元测试除了由程序的作者来写,还需要由其它人去编写(最好是专业的测试人员)。

对于一些容易出错的、只有程序作者自己知道的、难以构造的样例,只能由程序的作者亲自出马去编写单元测试。

除此之外,当程序通过随机测试样例后,剩下的测试样例必然是通过构造来检验各种 corner cases。正所谓当局者迷,旁观者清,程序的作者很可能因为太过于熟悉一些细节的实现,而忽略此时可能存在的 bug。

例如:Codeforces 的 Hack 机制,OO 课程中的互测机制。

程序的每个模块都应存在对应的设计文档,其中包含输入范围、相应条件和产生的效果等,专业的测试人员可以根据这些信息,将这个模块当作一个黑盒,编写相应的单元测试。相比由开发人员编写的单元测试,样例的强度和覆盖率必然会更高。

问题二:使用随机数出现错误时,为何不能重现?

问:如果用随机数以增加测试的真实性,好么?

答:一般情况下不好,如果某个随机数导致程序出错,但是下一次运行又不能重复这一错误,则于事无补。我们还是要用随机数等办法「增加测试的真实性」,但不是在单元测试中。单元测试不能解决所有问题,不必期望它会发现所有的缺陷。

——《构建之法》第 2 章 2.1.2 好的单元测试标准

如果我们用 srand(time(0)) 之类的生成随机数,那确实难以复现,因为不同的时间、操作系统都会有不同的表现。

如果使用一个稳定的随机数生成器,即当种子确定时,接下来每个随机数都是固定的。通过不断更换种子以实现随机性,出现错误时只需要保留这个种子就可以重现错误。

一个例子是 testlib 中的 generator,testlib 是一个在算法竞赛中广泛使用的评测库,generator 是其中的数据生成器,它的种子只取决于运行时传入参数的哈希值,当发现错误样例时可以将传入时的参数保留,从而有效实现复现。

问题三:结对编程中,两人角色为何要互换?

结对编程中驾驶员和领航员的角色要经常互换,避免长时间紧张工作而导致观察力和判断力下降。

——《构建之法》第 4 章 4.5.3 不间断地复审

结对编程中,为追求产出比达到最大化,我认为应让编码能力更强的一方作为驾驶员,综合能力更强的另一方作为领航员。

如果说角色互换可以避免长时间紧张工作而导致观察力和判断力下降,那是否意味两个角色需要专注的程度不同呢?如果是这样,那其中一个角色的作用就会大打折扣,就失去了结对编程的意义了。

此外,两人的代码风格不完全相同,频繁的角色互换势必会让代码中各处风格迥异,即使两人可以频繁交流也不能避免(毕竟总不能领航员说一句驾驶员写一句,那还不如直接角色互换)。而代码风格的不同就会加大 bug 产生的几率,这是因为对一段代码最熟悉的人一定不是它的编写者,其它人即使一直在复审也可能会产生对细节上的误解,此时产生的 bug 可能会耗费更长的时间去修复。

结对编程在 ICPC 竞赛中也有类似的应用,ICPC 竞赛是三人一机的模式,当比赛进入最后一小时的封榜阶段,无法看到别人的提交是否通过,这个阶段选手感受到的压力是最大的。此时一个很常用的策略也就是「不要多开」,即一个人进行编码,其它两个人停止思考其它题目,而是一起查看正在编写的代码,两双眼睛共同复审代码,最大程度保证没有 bug 出现。此时,如果频繁切换编码者,那么代码极容易变得千疮百孔,大概率这道题也很难在预定的时间内通过。

当然,这个问题的提出很可能是因为我总是那个「编码者」,希望在经历过规范软件工程下的结对编程后,我可以得到这个问题的答案。

问题四:书中的冲刺部分是否适用于我们的课程?

在冲刺期间,外部人士不能直接打扰团队成员。一切交流只能通过 Scrum 大师 (Scrum Master) 来完成。这一措施较好地平衡了「交流」和「集中注意力」 的矛盾。有任何需求的改变都留待冲刺结束后再讨论。

——《构建之法》第 6 章 6.1 敏捷的流程介绍

根据 PPT 上的时间安排,两轮开发的冲刺时间均为两周。在冲刺前的一周,功能规格说明书和设计文档都已经完成。

「软件工程」这门课对于大三的我们来说,某种程度上属于「兼职」。我有十足的热情投入大量时间到其中,但是其它课程的存在可能并不完全允许我这样做,因此很难做到每天都在疯狂冲刺。此时,冲刺这个过程真的可以有助于我们在开发过程中集中注意力吗?

此外,长达两周的时间里,我们都无法改变需求吗?对于一个大型的公司,开发团队和需求分析团队是高度解耦的,前者只需按照给定的需求不断冲刺。然而对于我们的课程,每个团队仅由 5-7 人的大三学生组成,根据往届经验每个人都会身兼数职。相关经验不足的我们若在冲刺开始前确定了不那么合理的需求,一定要硬着头皮做出来在冲刺结束之后再进行调整吗?

问题五:工程师不等设计师的线框图怎么开始工作呢?

用户体验和用户界面设计的目的是什么?有哪些步骤呢?一些没有经验的工程师觉得,「我先把代码写好,然后有一些会画图的人来把界面改一改就好了……」,这种想法是非常幼稚和有害的。另一方面,如果认为工程师只能等着设计师的线框图才能开始工作,这也是同样幼稚的。

——《构建之法》第 12 章 12.2 用户体验设计的步骤和目标

我的理解是,设计师的线框图就是需求的细节体现,如果连需求都不知道是什么,工程师写什么呢?

此外,「我先把代码写好,然后有一些会画图的人来把界面改一改就好了……」,这句话我认为并不是完全错误的,如果将开发工作分为功能开发和美工两部分,如果能让这两部分足够解耦,是否就能实现这句话的愿景了呢?

问题六:真的有用户嘛?

作为一门大学课程,课程结束后,同学们开发出来的项目并不一定要强求发布后长期运行并维护。

事实上,往届大部分项目在课程结束后就就结束运行了。然而,我们将要开发的项目将要面对真实的用户,如果我们的项目在今年 6 月后就不会运行了,那么真的会存在想使用我们产品的用户吗?如果我们做的是这样的产品,那它的用户量真的有意义吗?

想要获得真正的用户,我目前只能想到两个方向:

  • 为学校服务,包括:
    • 为课程服务,包括航概刷题库、课程平台等。
    • 为学校服务,包括教务系统、投诉平台等。
  • 进行小型的创业。

是否有更加合适、便于实施的方法呢?

调研源代码版本管理软件

我选择调研使用过的三个平台:GitHub、GitLab、Gitee。

相同点

均以 Git 为核心,并配套了大量相关功能,包括但不限于:

  • 基础的 Git 远程仓库功能。
  • 对 Git 中一些功能的可视化,例如查看 commit 记录。
  • 在线浏览仓库文件结构。
  • 对部分文件的在线的预览,例如 Markdown 文件。
  • 权限管理。
  • 提 Issue。
  • Fork 仓库。
  • 社交功能,例如 star 仓库。

不同点

GitHub

GitHub 多为开源项目,一般不能直接对他人仓库的代码进行修改,若要想进行更改,一般使用 fork + pull request 的方法。

即想要对一个项目的代码进行更改时,先将其 fork 为自己的仓库,对其进行修改后,发起 pull request。原仓库的开发者将其审核后,若认可修改,则将对应分支 merge 到原仓库中。

Github 的公有仓库和私有仓库均为免费,且不限制协作人数,但对于高级功能、企业级功能或者需要个性化支持团队,则需要付费。

GitLab

GitLab.com 由官方搭建,公有仓库和私有仓库均为免费,且不限制协作人数。

此外,团队内部也可以在自己的服务器上自行部署 GitLab,实现对仓库的完全掌控以及自定义,这也是 GitLab 的相比 GitHub 和 Gitee 的重要区别。

因此,GitLab 的使用者多为私有的团队项目,一般使用新建分支 + merge request 的方式实现项目的多人合作。

即想要对主分支的代码进行更改时,先将其复制到一个新的分支,对其进行修改后,发起 merge request。审核者查看后,若认可修改,则将其 merge 到主分支中。

事实上 pull request 和 merge request 本质是相同的,但因为两个平台的用户需求不同,其命名和显示有所不同。

Gitee

Gitee 相当于一个「国内版」,它的功能和 GitHub 非常相似,主要面向国内用户。

近年来,GitHub 因为一些原因无法顺畅直连,服务器位于国内的 Gitee 有时是一个合适的选择。

Gitee 公有仓库和私有仓库均为免费,公有仓库协作者数量不限,但私有仓库在不付费的情况下至多有 5 个协作者。同样支持付费以享受企业级功能。

调研持续集成/部署工具

我使用了两个 CI/CD 工具:GitHub Action 和 GitLab-CI。

使用 GitHub Action 模拟完整的出题流程

仓库地址

Polygon 是一个被广泛使用的算法竞赛出题平台,其提供的完整出题流程如下:

  • 使用 generator 和脚本指令生成输入数据。
  • 使用 validator 检验每个输入数据是否合法。
  • 使用 Main correct solution (标程) 为每个输入数据生成正确的输出数据。
  • 对其它每个 solution,为每个输入数据生成其输出数据,使用 checker 和上述得到的正确输出数据检验该 solution 的正确性。

整个流程需要库 testlib.h 的支持。

CF1559E 为例,我挑选了 10 个数据生成脚本、generatorvalidatorchecker、以及我的 Main correct solution 和一位验题者的正确 solution,模拟上述流程。

workflows 代码

name: test
on:
  push:
    branches:
      - main
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
        - uses: actions/checkout@v2
        - name: compile
          run:  |
           g++ checker.cpp -o checker
           g++ validator.cpp -o validator
           g++ generator.cpp -o generator
           g++ solution1.cpp -o solution1
           g++ solution2.cpp -o solution2
        - name: run-generator
          run: |
           ./generator 50 100000 96010 > 1.in
           ./generator 50 100000 97001 > 2.in
           ./generator 50 100000 97002 > 3.in
           ./generator 50 100000 97003 > 4.in
           ./generator 50 100000 97004 > 5.in
           ./generator 50 100000 97005 > 6.in
           ./generator 50 100000 97006 > 7.in
           ./generator 50 100000 97007 > 8.in
           ./generator 50 100000 97008 > 9.in
           ./generator 50 100000 97009 > 10.in
        - name: run-validator
          run: |
           ./validator < 1.in
           ./validator < 2.in
           ./validator < 3.in
           ./validator < 4.in
           ./validator < 5.in
           ./validator < 6.in
           ./validator < 7.in
           ./validator < 8.in
           ./validator < 9.in
           ./validator < 10.in
        - name: run-solution1
          run: |
           ./solution1 < 1.in > 1.ans
           ./solution1 < 2.in > 2.ans
           ./solution1 < 3.in > 3.ans
           ./solution1 < 4.in > 4.ans
           ./solution1 < 5.in > 5.ans
           ./solution1 < 6.in > 6.ans
           ./solution1 < 7.in > 7.ans
           ./solution1 < 8.in > 8.ans
           ./solution1 < 9.in > 9.ans
           ./solution1 < 10.in > 10.ans
        - name: run-solution2
          run: |
           ./solution2 < 1.in > 1.out
           ./solution2 < 2.in > 2.out
           ./solution2 < 3.in > 3.out
           ./solution2 < 4.in > 4.out
           ./solution2 < 5.in > 5.out
           ./solution2 < 6.in > 6.out
           ./solution2 < 7.in > 7.out
           ./solution2 < 8.in > 8.out
           ./solution2 < 9.in > 9.out
           ./solution2 < 10.in > 10.out
        - name: run-checker
          run: |
           ./checker 1.in 1.out 1.ans
           ./checker 2.in 2.out 2.ans
           ./checker 3.in 3.out 3.ans
           ./checker 4.in 4.out 4.ans
           ./checker 5.in 5.out 5.ans
           ./checker 6.in 6.out 6.ans
           ./checker 7.in 7.out 7.ans
           ./checker 8.in 8.out 8.ans
           ./checker 9.in 9.out 9.ans
           ./checker 10.in 10.out 10.ans

运行截图

github-action-1

使用 GitHub Action 自动部署组队训练 Wiki

仓库地址

Wiki 地址

基于 mkdocs-material。

workflows 代码

name: mkdocs-deploy
on:
  push:
    branches:
      - main
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: 3.x
      - run: pip install mkdocs-material
      - run: mkdocs gh-deploy --force

运行截图

github-action-2

github-action-3

使用 GitLab-CI 自动部署组队训练 Wiki

仓库地址

Wiki 地址

基于 mkdocs-material。

.gitlab-ci.yml 代码

image: python:latest

before_script:
  - pip install mkdocs-material -i https://pypi.tuna.tsinghua.edu.cn/simple

pages:
  stage: deploy
  script:
    - mkdocs build --site-dir public
  tags:
    - docker
    - tencent
  artifacts:
    paths:
    - public
  only:
  - main

运行截图

gitlab-ci-1

gitlab-ci-2

对两种工具的看法

GitHub Action 和 GitLab-CI 都是目前被广泛使用的 CI/CD 工具,通过编写相应的脚本文件,就可以在推送源代码的同时进行自动化构建,极大地提升了效率。

GitHub Action 的 Runner 由 GitHub 统一配置,由于项目的开源性和很多脚本的通用性,GitHub 上创建了一个关于这些脚本的 Marketplace,进一步简化了特定情况下的使用复杂度。

对于 GitLab-CI 来说,若使用 GitLab.com 上的 Runner 需要进行信用卡认证,较为麻烦。因此大多数情况需要自行搭建 Runner。

由此可看出,若开发一些小型项目,使用 GitHub Action 更加快捷、方便,使用 GitLab-CI 则会相对麻烦一些,而且如果 Runner 所在的服务器配置不行还会出现构建的问题。

相反,开发大型团队项目时,GitLab-CI 更加实用,一方面可以使得整个构建流程都在团队的掌控之中,另一方面有着足够优秀的服务器配置用来运行多个 Runner,每次不需要排队等待,可以直接构建。

由此可得,GitHub Action 更适用于小型、开源的项目,GitLab-CI 更适用于大型、私有的项目,这完美契合于 GitHub 与 GitLab 各自的特点。

posted @ 2022-03-11 18:16  JJLeo  阅读(118)  评论(4编辑  收藏  举报