[2019BUAA软件工程]个人期末总结感想
写在前面
经过一学期对于软件工程的学习,笔者完成了一次结对编程以及三个周期的敏捷开发流程。在本博客中笔者对于一学期的学习进行了总结,并对于自己最初的疑惑做出了回答。
笔者在学期开始前应课程要求通读了邹欣老师的《构建之法》一书,并对软件工程进行了一定的调研,提出了几个问题。这是该博客的链接。
对于问题的回答
经过了一学期的学习,笔者从理论和实践多方面对于软件工程的开发进行了学习。对于学期初提出的一些问题也逐渐有了自己的回答。以下为笔者现在对于这些问题的看法。
- 个人开发流程(Personal Software Process)自身的时间开销?各个阶段边界的界定?
这个问题对于量化评估软件开发过程来说十分重要。但在就笔者以前的开发经验来说,准确地计算开发中每一阶段的时间是十分困难的——在开发过程中很多时候是设计、开发、测试等阶段交叉地进行。这导致同时进行时间记录会很忙麻烦。
在结对编程时,笔者专门地对个人开发流程进行了量化。在课程的要求中,需要在开始开发时就需要对PSP各个阶段的时间开销进行前期的预计,并在之后的开发中按照计划中的时间展开各个阶段的工作。在开发过程中,由于有了PSP时间开销计划的限制,笔者在结对编程的每个阶段的时间把控上有了一定的目的性。尽量在预计的时间内完成相应的工作。如果实际使用的时间有所偏差,事后也能更好的分析。
回到问题上,如何才能更好地界定各阶段的边界,更好地量化开发的时间开销呢?在笔者进行结对开发时大部的时候都是由一开始做的计划驱动的。也就是限定一段时间,专门地完成一个阶段的工作。如果能一直按照计划完成开发(最好的情况),那么计划便是最终个人开发的时间开销。当然在结对编程的过程中,笔者和队友也遇到了许多意料之外的问题,并没有完全按照计划的时间完成各阶段的工作。比如在设计上花费的时间少于计划的时间而开发和测试花费的时间稍微多于计划的时间。此时,只需以计划的时间开销为基准进行微调即可。
总的来说,对于个人开发流程的时间开销的量化让笔者在开发过程中对整体的进度和时间有了更多的把控,也能够根据产生的偏差反思自身每个阶段的问题。
- 优化与泛化的时机。
何时优化代码?何时抽象泛化代码?这两个问题笔者至今也没有比较准确的答案,或者说只能视情况而定。
在笔者进行结对编程的时候基本没有进行泛化,更多的是优化。这主要是因为结对编程的程序不需要面对很多需求上的改变,所有的要求一开始就已经确定了。在此之上,程序对于运行效率上的要求很高,需要一开始就注意代码上的优化,否则十分影响最后的优化效果。
在进行团队开发时,情况就完全相反了。由于需要进行三次迭代周期,面对变化很快的需求,程序需要有较高的可延展性。于是要求更早地进行泛化,按照功能进行抽象,编写相应地通用功能模块。而过早地优化可能并没有太多的收益。
- 结对编程两人的分工以及轮转效率问题。
对于这个问题,笔者在结对编程的过程中就遇到了。由于两人时间上的安排以及开发的子问题的特性,笔者和队友采取了结对编程结合独立开发的方式。笔者在结对编程的总结时对于分工以及轮转效率问题就给出了自己的看法。
结对编程和分工开发就好比单线程与多线程。当任务的工作量较大,并且各模块的开发任务能分解为并行度较高的子任务的时候,很明显进行分工“多线程”开发的效率会高一些。再基于上一条,在面对工作量较大的任务,结对编程很有可能会在推进开发进度上出现困难。在笔者结对编程的前期,两人编程的效率是比较可观的,很快就完成了基本功能。但随之而来的测试、优化、回归测试、GUI绘制等等任务使得本来时间就不太富裕的结对编程出现的进度推进上的困难。最终笔者两人将部分任务的任务进行了分工开发,缓解结对任务的压力。
结对编程是一种多人开发的方法。然而并不是所有的情况下都适合结对编程,需要结合实际情况来进行取舍。在选择开发方式、决定分工时需要对于产生的开销进行预估。当预期的效率不尽人意时可以考虑融入其他的开发方式,或者直接改变开发的策略。
- 敏捷开发中的任务规划与推进问题。
在团队开发过程中,笔者没有担任项目经理(PM)的角色,但在α迭代时协助过项目经理的工作。和《构建之法》一书中讲的相同,Scrum是靠每个成员的能动性推动的,而项目经理主要进行整体上的信息传递,保证团队各部分的协作。对于任务的规划,更多地是通过小组成员一同讨论完成的。这样的话,一是能够比较完备地完成规划;而是避免了转述任务时可能产生的差错。对于项目推进的问题,在每个成员能动性的基础之上,还需要项目经理、每个成员之间真实地沟通。在笔者的团队中就出现过有困难不提出、虚报自身进度等情况,影响项目进度的同时也使得合作变得十分不适。
总而言之,最重要的就是沟通,把问题摆到台面上让大家一起讨论。让每个成员都参与到任务规划和项目推进上,提高每个人的参与度和能动性。
- 团队开发中个人效绩的评定。
本学期,笔者先后在两个团队中参与了软件的开发。每个组都有不同的个人效绩的评定方式。事实上没有最好的效绩评定方式。在一个小组中,能够让每个人都能够接受的评定方式就是很好的。应课程组的要求,在进行开发之前,每个小组都对于个人效绩的评定方式进行了讨论,保证了评定方式都能为组员所接受。
软件工程开发总结
在这一部分笔者将会从软件工程开发的六个阶段总结自己的体会。
需求分析——使用NABCD分析框架
对于需求分析这一阶段,《构建之法》一书提出了NABCD分析框架,从原始需求、采取做法、给用户的好处、竞争对手和推广方式五个方面进行项目的需求分析。在团队项目立项后,每个小组都按照NABCD五个方向对于项目的需求进行了调研。这一需求分析方式较全面地衡量了项目的目标、潜力以及可能遇到的障碍,使得项目开发的重点更加明确。比如在对笔者团队的项目进行分析后发现最大的困难在于推广上。于是团队需要将更多的经历用于推广以及使用群体的建立上。
设计——在干活前先形成完善的文档
在完成需求分析后,最为重要的事便是根据需求形成一个完备可行的文档。在这一方面,笔者可以说是感受颇深。在笔者团队进行α阶段的初期,由于团队成员(包括笔者)缺乏一定的前后端开发经验,导致在设计接口文档时产生的一定的差错,形成的文档存在很多的缺陷。这导致后期开发的过程中需要频繁的重构接口文档,甚至到最后整个文档被废弃。这大大地影响了笔者团队的开发进度。
在设计阶段对于需求进行抽象,编写细化后的功能文档、前后端接口文档等等。这些文档相当于团队成员对于项目的契约,在后面的阶段中起到了领导作用。此外,文档的撰写还需要比较简洁,以避免产生文字理解上的偏差。团队在干活前很有必要进行讨论形成完善的文档。
实现——时刻按遵循设计文档
完成需求分析和设计后,团队的每个成员就要着手各自的任务。在实现阶段,每个成员很难频繁地对各自任务的边界进行讨论,而是根据设计阶段文档来保证每个自任务能够对接成整体。因而在实现阶段,严格按照文档上的契约进行开发相当重要。在β和γ阶段的迭代时,笔者转会到了另一团队担任后端开发的任务。由于有了α阶段的教训,在阶段冲刺之初笔者就和开发前端的成员协商好了中间的接口格式。随后前后端只需严格按照接口编写代码,就能够保证最终前后端功能的一致性,并且在开发过程中免去了很多不必要的讨论过程。
测试——完备的测试是关键
在测试阶段,笔者主要负责后端代码的单元测试。《构建之法》一书中提及了一种测试驱动开发的方式,即在实现阶段编写代码之前就设计了单元测试。笔者在开发时尝试了这种开发的方式。这种方式在代码编写完成的同时就保证了其正确性。除此之外,按照《构建之法》一书中所讲,笔者还在测试阶段进行了覆盖性测试等测试。完备的测试是产出高质量软件的基础。对于项目中的每个模块,往往需要使用更多的代码对其进行测试。
发布——尽早发布最小可用版本
敏捷开发的一大特点便是迭代迅速,这要求开发团队很快地给出能够使用的版本。这也就是说敏捷开发不要求团队一次性给出最终版本的软件。在《构建之法》书中对于每个阶段团队需要给出的软件的要求有以下的描述:
Alpha阶段:指集成了主要功能的第一个试用版本。在这个版本中有些小功能并未实现。事实上很多软件的Alpha版本只是在内部使用。给外部用户使用的Alpha版本会起一个比较美妙的名字,例如,技术预览版(Tech-nical Preview),等等。
Beta阶段: 功能基本完备,稳定性较Alpha版本高,用户可以在实际工作中小范围使用,可以有Beta1、Beta2、Beta3……
ZBB阶段(Zero Bug Build):某天的版本要把在之前(例如48小时前)记录的Bug都解决掉。
RC阶段(Release Candidate):发布候选版本,RC1、RC2……直到RTM为止,版本间隔时间较短。
RTM阶段(Release To Manufacturer):最终发布版本。如果某一个RC版本没有很大的问题,那么这一RC就会成为最终的版本,通常情况下,软件公司会把最终的版本和相关的文件及其他资料交给另一个团队(Manu-facturer)去包装、刻制光盘。在AppStore/Marketplace的年代,我们有相应的RTM(Release To Market)。
RTW阶段(Release To Web):和RTM类似,对于网络应用来说,我们无须依赖“Manufacturer/Market”制作软件的光盘或者管理软件的发布渠道,但是要依赖“Web”来发布我们的最终版本。如果软件产品是一个网站服务,则一般会交给网站运营团队(Opera-tion Team)去管理,这样的发布也可以叫做RTO(Release To Operation),运营团队和研发团队一起决定什么时候系统上线(Go Live)。把软件提交到各个应用商店则可以称为Release To Store。
在团队开发中,笔者经历了其中Alpha、Beta以及Gamma阶段。其中在Alpha阶段,团队主要还在磨合期,经过近一个月的时间给出了软件的雏形,实现了基本功能和部分“杀手功能”。而在Beta阶段则是在对已有雏形进行完善:修复已有问题、按照需求增添功能。而Gamma阶段就类似于RTM阶段,基本上是将前两个阶段的软件进行收尾工作,有针对性地完善。
这每个阶段的持续时间够不算长,旨在尽快发布可用版本供用户使用。只有用户真正地用了软件,才能够获取到最真实的反馈。这是问卷调查等调研方式没法达到的。
维护——及时响应用户的反馈
在发布可用版本的软件后,团队中的维护小组需要及时地获取用户的反馈,监测实际需求的变动,以及时改变软件响应部分。在γ阶段时,笔者参加的团队接了一个外校的软件开发请求。在软件发布投入用户测试之后,很快就收到了很多用户的反馈,涵盖从UI到功能各方面的建议。在汇总了反馈之后,团队成员对建议进行了取舍,并很快地对软件进行了更新。
及时地根据用户的反馈进行维护,能够使软件与用户的实际需求更加紧密。除此之外,在维护阶段,不定期地对软件进行测试能够发现并修复隐藏的问题,增长软件的寿命。
一学期的回顾
在一学期的软件工程的学习中,笔者共经历了一次结对编程和三个团队开发的迭代周期。通过各样的软件开发实践,笔者在软件开发方式以及编程能力等方面上都有颇多收获。
在编程能力上,由于在Alpha阶段后进行了转会,笔者一共在三种环境下进行了开发工作。在结对编程期间,笔者和队友采用了C++作为编程语言。而在团队开发期间,笔者先后学习了PHP的Laravel框架和Python的Django框架。此外,笔者还解除了前端的部分开发语言。这大大地充实了笔者的开发技术栈,丰富了前后端开发的模式与技巧。尽管如此,笔者主要还是负责后端部分的开发工作,对于后端代码运作机制、后端数据抽象、后端向前端交付等都有了更加深刻地认识。
对于软件工程,笔者最为深刻的认识就是纯编程的工作在整个项目中并不是最为重要的。在软件开发尤其是团队开发时,非编程的工作常起到十分重要的作用。在团队开发时,笔者和队友花费了很多的时间在调研、讨论、沟通、设计等等工作上。而这些工作则是为开发工作打下基础。笔者很明显地能够感觉到,当这些非编程地工作都做得十分充分时,开发工作推进起来会十分轻松。在Alpha阶段时,笔者的团队正是由于沟通等工作做得不够充分,导致最后开发工作出现问题。虽然在这个过程遇到了不少的问题和挫折,但是笔者也收益颇深。过这一学期的开发,笔者对于软件工程开发中,各种阶段的工作有了更加深刻体会。