$$ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Self-defined math definitions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Math symbol commands \newcommand{\intd}{\,{\rm d}} % Symbol 'd' used in integration, such as 'dx' \newcommand{\diff}{{\rm d}} % Symbol 'd' used in differentiation ... $$

提问回顾与个人总结

项目 内容
本作业属于北航 2020 年春软件工程 博客园班级连接
所属教学班 006
本作业是本课程最后一次个人作业 作业要求
我在这个课程的目标是 收获团队项目开发经验,提高自己的软件开发水平
对应的博客 博客链接
这个作业在哪个具体方面帮助我实现目标 回顾整个学期的软件工程课程学习历程,总结经验

回顾问题

是否需要一个中间人作为软件工程师与用户之间的沟通桥梁

  • 在 2.3 节中,作者列出了大学四年级生与有经验的软件工程师的个人开发流程对比数据,其中可以注意到,软件工程师对于需求分析更为重视。对此,我有一些想法。

    需求分析是连接用户和开发者的重要桥梁,但是用户和开发者对于需求的着重点可能会有区别。因此,是否需要一个中间层帮助用户和开发者更好地完成需求分析,换言之,将需求分析的任务从软件工程师中剥离出来,让中间层作为这一环节的主要负责人,软件工程师以协助的身份参与到需求分析中。

  • 实际上,这一角色一般是由产品经理充当的,由产品经理负责市场调查并根据用户需求决定开发的内容。当然,产品经理的职责一般不仅于此,往往在产品整个生命周期中都有相关的任务。

  • 然而在第五章关于流程等部分又提到了瀑布模型、瀑布模型的各种变体、统一流程(RUP)等。在瀑布模型中,各步骤是可以进行回溯的;在RUP中,需求分析、设计、实现、测试、部署工作流又渗透到了初始、细化、构造、交付四阶段中。

    这看起来有些矛盾——我们当然可以概略地说软件的生命过程中包含了需求分析、设计、实现、测试、部署这些阶段,但将其按第一章讲成是一个线性过程、或按RUP来说各个步骤在时间上有并行重叠,似乎都不是定数。确实,软件的生命周期可能并不是完整的一个Cycle,也很可能不只包括一个Cycle。但实际上可以认为,在软件构建过程中,充满了大大小小不同粒度的“周期”。

    因此我认为对软件的生命周期的定义是不确定的。首先无论是按哪种模型,似乎这些步骤都不是一个重复的Cycle。其次具体的软件流程是按照需求和产品特点不断调整的,没有一个固定的、通用的流程。

    综上,我认为软件的生命周期是不固定的,且不能被称为“周期”。如果偏要给定一个整体的流程,我认为按照RUP四阶段的粗划分比较合理。

结对同伴的选择

  • 在 4.5 节中,作者介绍了结对编程的含义及其有效性。但是考虑到结对编程会涉及到人与人之间的密切交流,我认为在选择结对伙伴时需要解决以下的一些问题。

    首先,是两人的软件工程水平差距。如果两人的水平悬殊,一位是经验丰富的高手,另一位是初涉职场的新手,这种情况下的结对编程毫无疑问会演变成为高手的个人表演,新手的参与程度会比较低。而如果两人的水平相当,如何能够保证两双相似的眼睛的 review 结果能够优于单独编程,不致于浪费人力。

    其次,是两人的性格差异。每一位开发者都有自己的偏好,无论是代码的品味、编辑器的设置等与编码相关的,还是待人处事等与人际交往相关的,都可能会产生冲突。如何避免与解决两位开发者之间的冲突,我认为这是一个难点。

    契约式设计是一种保障代码质量的手段,其思想是使用某种特殊的语言对接口函数的行为和约束(前置条件、后置条件、不变式等)进行建模和描述,并在编码后对代码进行静态检查(static)、运行时检查(run time)等。

    • 先验条件:为了调用函数,必须为真的条件,在其违反时,函数决不调用,传递好数据是调用者的责任。
    • 后置条件:函数保证能做到的事情,函数完成时的状态,函数有这一事实表示它会结束,不会无休止的循环
    • 不变式:从调用者的角度来看,该条件总是为真,在函数的内部处理过程中,不变项可以为变,但在函数结束后,控制返回调用者时,不变项必须为真。

    但是这种设计在我们目前的思路中存在很多缺点:

    1. 程序契约不能代替程序编写,良定义的接口并不意味着会有良定义的实现

    2. 程序契约

      不能代替单元测试

      ,良定义的接口并非全都可以规范为单元测试

      • 如我们常说的forall, exists等量词,良定义,但是很难做测试
    3. 契约本身的长度超过了代码,而复杂的代码又难以用契约约束

  • 由于疫情的影响,我与结对同伴并没有真正地在近距离进行结对编程,仅仅是依靠着微软的 Live Share 进行协作。两人的交流是隔着屏幕进行的,存在着缓冲时间,这种形式下其实很难真正地了解到对方的习性,很难有爆发冲突的点。因此,就结对编程体验而言,我认为是不足的。

测试方式的选择

  • 第 12 章与第 13 章分别讲述了用户体验和软件测试,在一个开发周期内,软件测试应是在用户体验之前进行。但是,现在似乎有着其他的测试方式,即让部分用户作为小白鼠的方式进行测试。

    Windows 10 有 Windows Insider Program,参与到该 Program 的用户可以提前一个大版本体验到 Windows 10 的新内容。但是 Insider 版本是不稳定的,用户以稳定性为代价换取了新体验,同时向微软反馈使用体验与 bugs。显然,这种方式有效地削减了企业在测试方面的成本,但是用户测试难以覆盖到所有可能的代码执行路径,这导致了正式版本发布时仍可能存在着会影响用户体验的 bug。这种利用用户进行测试的策略是否合理?

    我们的团队测试方式:

  • 经过团队任务的训练,我们发现,如果产品是直接面向终端用户的,面向的用户是不确定的、无法及时获得反馈的,还是需要在发布前就完成充分的测试,否则会直接影响用户的体验,甚至在产品的后端留下错误的数据,致使后期的修复困难。

测试人员是否需要对代码有了解

  • 在 14.2 节中,作者讲解了独立测试人员的重要性。但是,我对此有一些疑问。

    测试人员对于代码的熟悉程度远不及开发者,可能会以用户无法达到的方式来调用 API 进行测试,这些时候可能就会导致不存在的 bug 产生。这种情况下,是否需要让测试人员对代码的结构有一定的了解?

  • 其实这个问题不应该落在测试人员上,而应该落在开发人员。对于一段运行着的代码,我们无法期待它在之后某一次的产品迭代中不会引入新的依赖或成为新模块的依赖,如果这段代码本身就可能存在着产生 bug 的执行路径,那么就可能会引入 bug,以后溯源问题的时候可能会默认这段代码是正确的而错过从而浪费人力物力。

实践中的收获

需求

认识到了需求分析的重要性。对于用户的需求,我们要从中分析并总结出所需的功能,并对每一种功能的实现可能性与预期开销做调研,最后得到我们真正要实现且能够实现的功能。然后就可以据此开始开发,并且在开发时有无需考虑功能是否无法实现或者最后会被弃用,因为在前期已经做了充分的调研。

设计

设计是一切的基础,同时也是团队内讨论最为激烈的部分。我们需要考虑许多问题:我们要采用什么样的架构、我们需要使用什么框架进行开发、团队成员的技术栈是否能够支撑我们的选择以及学习成本有多高等等。在我们决定了采用前后端分离的架构、前端采用 Flutter 框架、后端采用 Django 框架之后,就得开始讨论前后端分别负责的功能、需要分割成多少模块、前后端交流通过什么方式进行、数据库表如何设计等等的问题,即进行规格设计。实际上,在完成设计之后,整个软件几乎已经完成了一半,后面的步骤就有点像“看图说话”了。

实现

我负责的是后端,与前端的对接主要是通过文档进行的,由此我深深体会到文档的重要性。在开发实际代码之前,我一般是先写 API 文档,说明每一个 API 的输入输出与异常返回等要素,然后由前端审阅是否能够支持前端的功能实现以及前端是否能够按照预设的方式调用 API 等等。这一步是很清晰的,而且也降低了与前端沟通的开销。

测试

后端的测试主要是单元测试与外部发包测试。实话说,我第一次感受到单元测试的复杂性,每一个模块都有着很多种可能的输入,“错误的输入各有各的不同”。刚开始时,我是先实现再编写单元测试的,但编写单元测试时往往会发现实现的一些纰漏,然后修改实现,甚至重构该功能,浪费时间,于是乎后来改为了先编写单元测试,然后以通过单元测试为目标来编写代码,这样的效率高很多。

发布

我负责的部分主要是服务器端的部署。我体会到了使用 Docker 进行环境部署的好处,每一次启动都是一个干净的环境,而且各种网络桥接非常方便,只需简单配置即可完成 Django+WSGI+Nginx 的部署。

维护

由于开发语言是 python,我对其不太放心,因此在代码实现中留下了比较多的 log,在出现 bug 时可以翻看 log 寻找问题出现的现场,非常方便。

理解与心得

在软工课程中,我的心得主要有两点。

第一点是开会的重要性。开会有很多作用,譬如 push 作用,每天一次的汇报可以使得大家更加重视并及时完成预定的任务。当然更重要的是交流作用,这毕竟是一个团队任务而不是单人闭门造车,大家可以互相了解进度,了解大家遇到的问题并讨论解决方案。某个功能不一定非得落在某个模块上,有时候可能另一个模块的负责人可以以更简单的方式解决这个问题,团队成员的技术栈互有差异,可能另一个人能够以另一种方式剖析问题,等等,集思广益。定时开会是一个让大家聚在一起的场合,这是最好的交流场合。

第二点是文档和博客的重要性。为了能够最好地表达自己的想法、表达自己的设计思路,将其写成文字是最好的,语言常常会因为时间限制而有所疏忽。文档是写给自己与团队成员看的,它迫使自己重复审视自己的思路是否能够符合其他部分的需求,也为其他成员提供了完整地了解作者思路的渠道。博客则是写给自己和外人看的,它提供了一个回顾总结自己工作的契机。

我相信软工课程的体会能够在日后得到实践。

posted @ 2020-06-17 22:15  I_love_SE_forever  阅读(225)  评论(3编辑  收藏  举报