项目 | 内容 |
---|---|
这个作业属于哪个课程 | 2020春季计算机学院软件工程(罗杰 任建) |
这个作业的要求在哪里 | 提问回顾与个人总结 |
我在这个课程的目标是 | 学习软件工程相关知识,培养自己独立和团队开发能力 |
这个作业在哪个具体方面帮助我实现目标 | 回顾并反思自己之前提出的问题,总结一学期以来在软件工程实践中的收获 |
作业正文...... | 见下文 |
其他参考 | 我以前的提问链接 |
1、回答以前的提问
(1)关于goto的用法
当时的问题如下:
在4.3节,讲代码设计规范的时候提到了 goto的用法,书中这样写道:
函数最好有单一的出口,为了达到这一目的,可以使用goto。只要有助于程序逻辑的清晰体现,什么方法都可以使用,包括goto。
然而,在大一的C语言课程中,任何一个老师在讲到循环的时候都会特别强调“尽量不要使用goto”,并且在Dijkstra的这篇文章中也提到了使用goto有着诸多害处,甚至想要提议在高级编程语言中废除goto。
由此我产生了疑问:是否应该使用goto语句呢?或者说什么时候使用goto是合适的呢?注意到书中提到了一个比较模糊的标准,即“只要有助于程序逻辑的清晰体现”,那么具体来讲什么样的goto才有助于体现程序的逻辑呢?(因为C语言课上老师们的观点一直都是“goto”会破坏程序的逻辑和可读性)
对于这个问题,现在看来是有点太钻牛角尖了。实际上,在我这一学期的开发过程中,很少遇到一定要用goto不可的场景,而且我担任的一直都是后端开发的任务,相比前端可以说在语句的逻辑上是更加复杂的。即使在这种情况下,我的循环语句中也基本用不到goto,简单的break和continue已经足够解决绝大部分的循环问题。出现这种情况,一方面归功于现有的开源项目框架非常多,这些框架往往有着完善的方法调用接口,很少需要我们写太多的复杂逻辑;另一方面也可以说明实践中必须用goto的情况确实比较少。
(2)关于类的使用
当时的问题如下:
在4.3.4节,谈到如何处理C++中的类的时候,作者提到了“仅在必要时才使用类”。但是在面向对象的编程中,提倡的是“万物皆类”的思想,这就产生了矛盾。固然,面向对象编程并不是在所有条件下都适用,但是C++本身是一门面向对象的语言,采用面向对象编程的方法无可厚非。那么作者这样“一刀切”式的下结论是否太过绝对了呢?
在个人项目和结对项目中,我确实使用了类,例如把直线、圆等图形都分别建立一个类,这样做的好处首先在于可以通过实现类中的方法来方便地进行功能的增加,此外,在进行单元测试的时候,也可以直接新建一个类的实例来调用其中的方法进行测试,达到测试某个特定函数的目的。现在再来看这个问题,我觉得我当时对“仅在必要时才使用类”的说法理解可能有些偏差。现在我的理解是,如果认为确实需要用到类那么就放心大胆的去用。C++本身虽然是一门面向对象的语言,但它还是兼容了C语言一些特性,因而不能做到完全的面向对象,所以要像java一样,甚至连main函数都要设为一个类那样的形式,在C++中本身就是不太可能实现的(如果不是有意而为之的话)。书中的这句话的初衷或许是要告诫我们类固然好用,但也不能滥用——像java一样把一切都设为类的做法在C++中是不可取的。
这里总结一下前两个问题。现在看来这两个问题都太注重文字的细节了,实际上软件工程是一门讲授工程化方法的课程,是要教我们如何开发出一个好用软件的工程化方法的,这其中包括项目管理、代码管理、质量管理等等。我认为,前两个问题可以归结为代码管理中的代码规范部分,而代码规范一般是由项目组在项目开始之前就已经制定好了的,不同的项目有着不同的要求,因而其代码规范也不尽相同。我们在实际进行软件工程开发的过程中,只要做到遵循代码规范开发即可,对于一些过于细节的部分可以不去或是少去关心一些。如何制定并遵循代码规范进行代码编写、谁以什么流程来审查代码是否符合规范,这是软件工程这门课更加关心的内容,而不是代码规范细节上的的内容如何。
(3)关于“创新者”和“先行者”的关系
当时的问题如下:
在16.1.4节,作者探讨了创新者和先行者的关系。作者提出,“大部分成功的创新者都不是先行者”,并举了很多领域的多家公司的例子来佐证这个观点。但我并不完全认同这个观点。我认为,成功的创新者之所以能够成功,是因为他们在某一领域做出了大胆的创新,这个创新是其他公司没有并且符合用户的需求和偏好的,例如一个新的商业模式、一个令人耳目一新的用户界面等等。从这个角度讲,它们也可以说是这个领域的先行者。教材上的“先行者”似乎被界定为了仅仅指技术上的先行者,我认为这是不够全面的,毕竟技术并不是关乎一个创新成功与否的最重要因素。
我现在其实能理解“大部分成功的创新者都不是先行者”这句话了。我们的团队项目,DDL Killer,我认为做的还是相当成功的,这一点从Alpha和Beta阶段的用户量和用户反馈都可以看出。但我们的团队项目其实没有用什么新技术,全是基于已有的框架——前端基于Vue,后端基于Django,因此在技术上并谈不上是“先行者”。但我们在解决用户需求这个层面上确实实现了创新,在这方面我认为是这个领域的“先行者”。例如,我们观察到北航课程中心存在的大量用户需求与使用起来诸多不便的矛盾,因此就想做一个app来优化同学们的课程中心体验,之后又结合Microsoft Todo的优点,开发出了我们现在的DDL Killer,可以说吸收了多个软件的优点而融合成了我们现在的项目。但是必须要注意到的是,如果不是有课程中心的使用复杂,我们是不太可能想到要优化这一点而推出我们的项目的;如果不是有Microsoft Todo的简单易用,我们也不会想到仿照它的一些功能去做我们的项目。这样看来,正是有了那些“先行者”的前车之鉴,我们才能在此基础上改进并创新,以推出更好的产品,这样与同类产品对比起来就会更有竞争优势,也往往更容易成功。
(4)关于创新的时机
当时的问题如下:
在16.2节,作者探讨了创新的时机,并提出了新技术基本都要经历的几个发展阶段,鼓励我们在观察到一门新技术出现或者正在被炒作的时候,能思考其正处于哪个发展阶段。但是我们知道,市场是有滞后性的,有可能大众正在追捧一门技术的时候,它却已经处于下降期了。那么如何才能真正地辨别出一个新技术所处的发展阶段呢?我认为,如果不是亲自去了解和参与到这门技术中,是很难得知它的前景到底如何的。
关于这个问题,我本学期没有什么机会去实际体会新技术发展的各个阶段,因此现在还难以回答。但软件工程是一门非常讲究实践的课程,这一点我在这学期的项目中体会是很深的,所以我现在认为如果想要彻底了解一门技术的前景如何,是要亲身去实践的。
(5)关于小故事“魔方的创新”
当时的问题如下:
在16.4节中,作者使用一个小故事,来讲述我们在创新的过程中要明确目标用户,并时刻注意自己是否在面向目标用户进行创新。故事之中有这么一小段情节:
果冻是学校里第一个学会了魔方口诀的,在学校这个小范围里姑且算一种创新,但是你的竞争力有护城河么——你能否保持只有你会背这个口诀?
在故事中,果冻和其他竞争者采用了发表论文的方式来实现这个“护城河”。但我有一个疑问:为什么不通过申请专利的方式来实现这个“护城河”呢——你要用我的技术可以,但得给我交专利费。这是不是一种更好的保护自己的创新的方式呢?
对于这个问题,其实在提问的博客刚发布不久,我就已经和老师在评论区讨论过了,当时讨论的截图如下:
经过讨论,我最终得出的观点是,虽然申请专利可能用处不大,但这也是保护自己技术的一种手段,我仍然认为申请专利是有必要的,毕竟能多一个证明的手段总不是件坏事。
2、新的问题
(1)有关前端和后端对接的问题
前端和后端对接的问题是一个相当费时费力的问题,我们组在Alpha阶段也因为这个问题而耗费了大量时间,直接导致了我们Alpha版本推迟了近一周才发布。
一开始,我们认为只要定好前端和后端交互的api和json格式,对接起来就能万无一失了,但实际上并不是这样。下面的这张图虽然可能有些夸张,但多少能反应一些前后端对接的问题:
可以看到,前后端虽然规定了使用RESTful api进行交互,并且前后端的开发人员分别都做出了他们认为的自行车的“前端”和“后端”部分,但两方对于前后端交接处显然没有商量好怎么做,导致最后做出这么一个有两个座椅的自行车。这种问题在软件开发的过程中是很常见的。
对于这种问题,我们小组采用的是开视频会议的方式,相当于让前端和后端人员“面对面”地沟通,尽量在视频会议中就将前后端交接的细节问题解决好,最好是能直接成功地进行前后端交互。这是我们组只有6个开发人员时的解决方案。但是,在真正的项目开发中,一个项目组显然不止这么多人,这样多人面对面沟通的时候就会有困难,甚至一个后端人员可能都不知道该找哪个前端人员去商量前后端对接的问题。于是我就想提出这个问题:
在真正的软件项目开发中,前后端对接具体是怎么做的呢?有没有一个规范的流程去确保前后端连接的正确性?或者有没有专门的组内几个成员来负责对接这部分呢?
3、学到的知识点
(1)需求阶段
进行NABCD的分析,尽可能全面地了解用户的需求,最好能确定哪些需求最重要,是用户的痛点,接下来就以这个需求为核心功能进行计划。
(2)设计阶段
设计主要分功能设计和规格设计。前者是给用户看的,即让用户了解产品的页面原型大致是什么样的、都能实现哪些功能;后者是给开发人员看的,目的是让开发者明确需要实现哪些接口以及实现的整体逻辑。设计阶段的设想可能很丰富,但要注意哪些是核心功能,这些功能在计划中应该尽快实现,最理想的情况是先设计出一个最小可用版本就发布。
(3)实现阶段
每天都要进行Scrum Meeting,了解各个组员的开发进度。作为PM,还需要把控项目的整体进度,为组员分配任务以及了解组员开发过程中遇到的困难,想办法及时给予帮助,以保证项目能如期交付。作为开发者,要严格按照技术规格说明书开发,并保证自己的代码符合代码规范。此外,要善用GitHub或是Gitee上的issue和pull request,及时记录自己的进度并迁入代码。
(4)测试阶段
进行单元测试,以快速定位可能出现bug的地方。每添加一个功能或是修复一个bug,最好进行回归测试,以保证其他功能未受影响,仍可正常使用。如果是访问量持续较高的网站,还要进行压力测试,确保高访问量的时候网站不会崩溃。
(5)发布阶段
要针对在计划阶段的目标用户进行推广和发布,发布时一定要重点宣传项目的核心功能、项目是如何解决目标用户的痛点问题的。此外,还要注意给用户方便快捷的反馈途径,以更好地改进项目。
(6)维护阶段
及时与用户沟通,根据收集上来的用户反馈进行维护和改进。如果有很大的更新,必要时可以重新发布新版本,或是在网页中以通知的形式及时告知用户更新内容。
4、理解和心得
(1)个人项目
个人项目中,我初步学会了使用GitHub进行个人代码仓库的管理,以及如何对自己的项目进行简单的单元测试。但是,由于是自己根据自己思路进行的测试,测试样例的覆盖范围和强度也有限,这导致了我的附加题还是出现了bug,而这个bug甚至是在结对编程的过程中才由我的同伴发现。这也反映了一个人编程时容易犯的错误,即思路比较片面,更容易出现bug。
(2)结对项目
结对项目中,我基本沿用了个人项目中的代码,并在此基础上进行了功能的增加。由于是我自己的代码,我的结对编程伙伴可能对代码并不熟悉,因此一开始我们采用视频会议的方式,由我为他讲解我的代码思路,之前提到的个人项目中的bug也是在这个过程中发现的。
我认为,结对编程最大的好处就在于能让一个人在打代码的同时另一个人可以进行代码审查,这样在编程过程中就可能会发现并修复很多bug,很大程度上减少了出错的可能。实际上,在团队项目期间,我们小组也将这样结对编程的优点融合了进去,采取了一种“多人结对编程”的方式,取得了不错的效果。当然,结对编程也有其局限性,最明显的就是它需要两个人约好了时间,并且在这段时间内都全神贯注地投入到代码中,这点有时候是比较难实现的,毕竟我们除了软工这门课程之外,还有很多其他课程也很耗费时间,两个人结对编程的时间也比较难约好。
(3)团队项目
关于团队项目的心得,我印象最深的就是我们团队自创的“多人结对编程”的开发方式了。具体来说,就是使用腾讯会议+共享屏幕的方式,一个人打代码的同时,其他几个相关的人同时进行代码检查。例如,一个前端同学如果编程过程中遇到困难,可以叫上另外几个前端人员和一个后端人员,来一起“多人结对编程”,这样前端同学可以为其指导前端的语法怎么写、组件如何调用,而后端的同学可以解决在前后端交互json格式上的一些问题,如果进展顺利,代码完成之后还可以直接部署在自己的服务器上,前后端同学一起测试,加快了debug的效率。
这也再次印证了软件工程是一门需要实践的学科。我们的“多人结对编程”就是在实践中摸索出来的一种适合我们组员的编程方式,其实软件工程的理论中,可能并没有规定得那么具体每个人要如何编程,很多东西都需要我们亲身去实践、亲身去尝试。书上说的方法可能只是前人的经验中效果还不错的方法,但不一定是最适合的方法,只有经过实践证明最有效的方法才是最适合一个团队的编程方法。
最后,我真的很高兴能和团队一起做出一个如此受欢迎的项目。虽然在开发的过程中遇到了不少困难,也有过不少熬夜的经历,但最后看到注册人数不断增长的时候的欣喜真的是无可比拟的。有很多同学都反馈说我们的项目很实用,会一直用下去,我们组员自己也一直在用我们的DDL Killer,尤其是现在这个大作业特别多的时期,它能够帮助我整理各科作业的ddl,并帮助我规划好自己的时间。
我们团队开发软件的初衷就是做出一个像样的、能流传的、实用的软件,现在看来这个初衷是实现了。