对抗代码遗忘的思考——提问回顾与个人总结

一、提问回顾

提问博客点这里

关于第一章中的“软件的非连续性”

经过这一学期的实践,我对软件的非连续性有了比较具体的认识。

在我们的项目中,后端涉及比较复杂的状态机,而可能一些小的输入变化就会触发状态机的改变,进而影响系统的运行状态。测试后端状态机是整个项目最困难、最复杂的地方,在这部分,软件的非连续性就体现得淋漓尽致。

而应对这种困难的方式也有很多,一方面,可以做充分的测试,尽量覆盖状态机的每一条状态转移路径,另一方面,在设计时也要做好充分的考虑,尽量让系统的状态数较少,转移数较少,从而使得系统的稳定性提高,易于维护和管理。

关于第二章中提到的“单元测试”

在学期初提出的问题是

是否有必要追求100%覆盖率的单元测试

经过这一个学期的实践,我觉得我找到了答案,测试是必需的,但100%覆盖率的单元测试既不必要,不也现实。

在这个学期的项目中,我们的产品从前端到后端涉及到了浏览器、服务器、Docker、文件服务器、磁盘文件系统。其中,很多功能都是需要多个组件协同完成的,而单独处于一个组件内部的单元测试常常无法兼顾整体,例如,在服务器系统内就很难监控到Docker的运行状态,相应的单元测试也就很难开展。因为不存在一个组件可以访问和控制到整个系统的每个组件,如果真的存在这样的组件的话,那说明系统的设计也是不好的,没有很好地实现系统层次之间的隔离,整个软件的耦合度比较高。

但是,这是不是意味着我们可以放弃对单元测试的要求而为偷懒找借口了呢?不是的。

首先,单元测试依然起着十分重要的作用,拿建筑楼房为例子,单元测试的作用就是保证每个砖块、每根钢筋的质量,虽然它很难保证整个楼房的蓝图设计是正确无误的,但是作为第一层保障,它可以有效地保证我们的最低层组件工作正常。

以我们的项目为例,在后端服务器实现中,会用到很多的工具类,这些类之间的耦合度很低,各自完成相关的一系列功能,为上层提供服务。单元测试在这里就可以发挥很大的作用,对每个工具类的每个方法进行全面的测试,可以为将来进一步的开发排除很多潜在的隐患。

而除此之外,我还认识到了测试不仅仅是单元测试这么简单,测试是一门学问,相应的也有诸多经典的测试方法,例如,在我们的项目开发后期,常常采用录制脚本的方式进行测试,通过浏览器录制一系列操作形成脚本,这个脚本可以重放,从而在软件开发过程中可以随时回归测试,保证之前脚本中包含的功能运行正常。

所以,总结来说,测试十分重要,但100%的单元测试往往不切实际,但在单元测试无法覆盖的地方,必须要有其他的测试手段进行弥补,要保证软件的每个环节都有相应的测试作为保障,才能在接下来的开发中保持软件的高质量。

关于第四章中提到的“结对编程”

在学期初提出的问题是

结对编程的开发方式开起来很美好,但是在实际团队开发中真的有广泛使用吗

经过本学期的结对编程实践,我依然对当初提出的问题持保留意见,也尚不能完全认同结对编程中的所有优点。

在书籍中介绍到结对编程有如下几个优点

  • 可以起到教学作用,技术高的程序员可以帮助技术较弱的程序员进步
  • 可以提高代码质量,因为代码的每个部分的质量都取决于一对程序员中在该方面技术较高的一个
  • 可以提高团队凝聚力,促进团队交流,利于团队管理
  • 可以有效应对团队人员变动

针对这几点,我也想谈谈我在实践过接对编程后的理解和困惑。

  • 可以起到教学作用,技术高的程序员可以帮助技术较弱的程序员进步

关于这个优点我完全认同,在接对编程实践中,我从搭档身上学到了不少东西,不论是编程技巧还是设计艺术,同时,我有时也能够为他提供一些帮助和想法,应该是完全起到了相互促进的作用。

但是,在这个优点背后有一个问题值得思考,也是我所困惑的。这样的时间成本是否较高,一方学到东西的代价是另一方需要停下开发的脚步,而且,并非每个人都有成为老师的潜质,有的人技术高超但是表达能力不强,让他们教授别人技术或许不如让他人查阅相关资料来的效率高。同时,编程和思维都是有节奏和状态的,打断编程者的连续输出其实对于编程人员来说是一件效率很低的事情,这样看来,这个教学作用的成本是否较高。

  • 可以提高代码质量,因为代码的每个部分的质量都取决于一对程序员中在该方面技术较高的一个

这个优点我也完全认同,但是,在我实践过程中的体会就是,达到这个最优往往会经历一番周转。

当双方在某个设计点上意见不一致时,需要停下进行分析,这本身没有问题,尤其是在双方技术水平相差较大时,一方会主导话题,从而使得问题的讨论和解决较快。而当双方技术水平相当时,问题就可能出现,可能双方各有不错的设计,但这两个设计相去甚远,说服任意一方接受理解另一方的设计都是比较困难的事情。其本质就是默契问题,是否双方有很高的默契度,编程和设计习惯上风格一致,这些都影响着结对编程的效果和实际性。倘若双方无法保持高度默契,那么有时时间就会被浪费在类似上面提到的场景上。

  • 可以提高团队凝聚力,促进团队交流,利于团队管理

这一点我完全认同,也认为十分实际,当下,很多公司也有技术茶话会这样的活动,目的也是为了可以一边交流技术、提高团队水平,一边也可以提高团队的凝聚力、促进团队交流。

  • 可以有效应对团队人员变动

确实有这方面的意义,但是我个人感觉这依然没有解决本质问题,这样的解决办法下,风险依然是在人员本身上,只不过将一个人变成了两个人而已。

而我认为更好的解决办法可以是完善相关的内部文档,每个人负责各自工作范围内的技术文档维护,这样可以有效地规避掉人员变动的风险。

这一点在这学期的强制转会中深有体会,据我了解,有的团队就将项目开荒初期的学习和技术文档维护了下来,从而使得转会新来的成员可以快速上手项目,团队的开发进度不会受到很大的影响。

关于第十六章中提到的“要成为领域的专家,才能创新”

在书中,作者的观点是这样的

这个想法看起来没什么错,我们不就是为了成为某个领域的专家,才来上学,拿学位,希望拿到学位之后成为专家,然后再开始这个领域的创新?但是统计数据表明,70%的创新者说,他们最成功的创新,是在他们的拿手领域之外发现的。

之后作者举出了HTTP的诞生阿里巴巴的诞生等例子,佐证上面的观点。

经过这学期的实践,我对这个观点有了一定的理解,也有了一些自己的看法。

在这学期,我们是自选项目,也算是做了一些创新性的设计实现,但是这背后是经过了一定的调研和学习才得来的。虽然不能说经过调研我们就成为了领域的专家,但是至少对领域有了一定的了解和认知,知道哪些是实现了的,哪些是空白的,哪些东西因为没人想到所以没人做,哪些东西因为难度太大所以没人做。

当然,作者的意思不是说对某个领域闻所未闻就企图在其中有所创新,而是说创新的领域不一定是自己最拿手的领域。这一点,经过这学期的实践,我有了全新的理解。

创新和实现不同,创新更关注的是要站在一个应用者和设计者的角度去思考,而不是实现者或者架构师的角度,它更多关注的是需要什么而不是如何实现。当然,这两者都十分重要,单纯有想法但无法实现也无济于事。但是,这背后正是作者想要表达的意思,不一定每个人都有实现某个东西的能力,但是每个人一定都有想到、想出某个东西的能力。

那我们的项目为例,我们发现在初学编程时,环境的配置很麻烦,IDE的安装很麻烦,所以我们想解决这个问题,于是我们提出了自己的WEB版IDE,对这方面的需求提供了一定的支持。这个创意源自于我们的真实需求,同样,那些伟大的创意,也往往来自于真实的需求。这正是作者想要表达和阐述的。

关于第十七章中提到的“磨合阶段”

经过这学期的实践,我发现没有磨合阶段的团队和无法磨合的团队都很少,以我们的团队为例,大家在最开始虽然意见不统一,但是经过一段不长的时间的调整和交流,很快大家在认识上就可以达成一致。

我认为,除了一些极端人员难以融入团队,可能会成为团队的害群之马以外,大部分时候,团队都是可以磨合和愉快合作的。

而在学期开始时,我提出了如下问题

如何判断一个团队是处于“磨合阶段”还是说这个团队的人员配置本身真的存在问题呢

针对这一点,结合我的实践体会,我认为,如果一个团队能够明确地完成分工,并且每个人都能够清楚自己的职责和任务,那么这个团队就可以继续合作下去。即使最开始存在团队成员的进度不能很好地达标的情况,但也依然可以认为团队的人员构成本身没有问题,是可以合作的。

因为如果每个成员都清楚自己的任务和职责,那么这至少说明了大家在工作和认识上达成了一致,在这个一致达成的基础上开展后续的合作都是有可能的。而倘若成员之间连分工和职责分配都无法明确,则要么是团队管理出了问题,PM没有很好地协调成员,要么就是团队成员无法达成一致,整个团队内对任务和目标没有一个清晰的认识和把握。

所以,我的理解是,团队成员之间能否对团队任务和目标有一个统一的认识和把握是可以作为评判团队人员配置是否合理的一个重要标准。

二、新的问题

实践出真知,经过一个学期的实践后,再回顾最初提出的问题,确实显得有些稚嫩和缺乏实践了。

不过在实践过程中,我也产生了一些新的问题,下面提出来和大家共同探讨。

如何对抗历史代码遗忘问题

这个项目总共历时2个月,从最初的搭建,到后来项目功能越来越多,鲁棒性越来越强,这其中都是需要进行代码的修改和添加的。

然而,在项目后期常常会出现一个情况,就是几周前的代码在几周后再次阅读时不能很快地回忆出其中的实现细节。

这里并不是想表达代码的可读性较差,即使是在充分利用面向对象编程和函数式编程的优势的情况下,回顾以往的代码依然要耗费一定的时间去阅读。

特别是在系统的状态较多较复杂的情况下,这种问题尤为明显,需要花费比较多的时间理清楚系统的状态迁移。

我认为,完备的设计文档和代码注释会有帮助,同时,设计多个小型专用系统来替代单一的多功能大型系统也会有所帮助。

但是我并无法满足于上述两种可能的解决方案,同时,因为问题暴露较晚,所以我也没有机会去实践检验上述办法是否真的有效。

所以在这里提出这个问题,希望能够得到帮助。

软件功能和软件安全性的矛盾

网络安全是一个很大的领域,而WEB应用依赖于网络,自然WEB安全也是一个很大的话题。

在项目初期,我们花费了不少时间在安全机制的设计上,甚至对于安全机制的考量一度影响到了我们正常功能与核心功能的开发进度。

我们每个人都承认,在软件领域,软件的安全性无论对于用户还是开发者都是十分重要的,它关乎双方的利益。但是,在能力有限,或是缺乏相应的专业技术人员的情况下,过多的安全设计考虑常常会影响到功能的开发。

所以,我很困惑应该将安全机制设计放在软件开发的哪个阶段。

倘若在最初软件设计时就将大部分安全机制考虑到并设计在最初架构中,那这样肯定会影响到软件的开发进度,特别是在缺乏专业技术人员的情况下。

而若不在最初设计时将安全机制考虑在内,而寄希望于在后期逐渐添加安全机制,那么很可能出现一种情况,就是为了添加安全机制,软件架构需要一些变动,这有时甚至会破坏单元测试的可用性,因为更高的安全性背后往往是更低的便利性,可能会有一些原本可以正常工作的单元测试不能在新的安全机制下运行,这就又给回归测试带来的困难,进而迫使软件开发进入了一种比较危险的状态。

所以,我很想知道,在有限的条件下,应该如何平衡安全机制设计和功能开发。

三、实践知识点回顾

需求阶段

在需求阶段,我学到的知识点是

需求调研不仅要保证提出的需求是真需求,同时也要保证我们的产品有优于同类产品的地方

我们的项目是WEB版的IDE,其实,这个领域的同类产品还是有不少的,但是我们在需求调研时提出了我们独特的地方,即面向新手

我们提出的需求是,许多新手初学编程时会被诸如环境配置、IDE配置等一系列配置工作阻碍,而我们的目标就是为他们消除阻碍,能够提供一个开箱即用的编程环境。

那么,我们提出的需求是真需求吗?是的。

据调查,很多大一新生在编程学习的前半个学期都会对开发环境有着或多或少的困惑和不解。然而理解这背后的一系列内容又本身超出了他们现有的能力范围,那么,我们产品的使用人群和使用场景也就应运而生了。

而我们的产品是否有优于同类产品的地方呢?是的。

根据调研,市面上大多数的WEB版IDE的功能都十分强大,基本涵盖了非WEB版IDE的绝大部分功能。但同非WEB版的IDE类似,这些WEB版的IDE依然使用难度较高,需要一定的经验,也需要一定的配置,并不能做的开箱即用,而这就是我们产品的优势。

设计阶段

在设计阶段,我学到的知识点是

有效地分隔任务为若干个子任务会有利于设计的进展

在我们项目最初的设计阶段,我们就将项目进行了分隔,粗略分为了前端、编辑器、后端这三个部分,而这三个部分又各自被分隔为若干个更小的部分,然后针对每个部分的功能需求去单独设计。这样,一方面有利于强化对于项目的整体把握,另一方面也有利于控制软件的复杂度,可以使得每个小部分都得到较优的设计和实现。

实现阶段

在实现阶段,我学到的知识点是

团队开发中的每日例会十分重要,有利于每个成员把握整体的开发进度

在alpha和beta阶段都有14天的scrum阶段,其中每天都要举行例会,在实现阶段的每日例会是十分重要的。

一方面,通过每日例会,每个成员都可以比较清晰地把握团队整体的开发进展,进而便于规划自己未来几天的任务。

另一方面,也可以起到监督和督促的作用,在每日例会上,大家都会汇报自己的工作进展,这在无形中就起到了督促作用。

此外,每日例会也能够起到活跃团队气氛、促进团队团结的效果,每日例会不仅是汇报工作的地方,也是团队成员交流的机会。

测试

在测试阶段,我学到的知识点是

要常常回归测试,不要等到最后统一测试,那样往往费力不讨好

在alpha阶段,我们的测试基本上是在发布前统一进行的,在开发过程中的测试较少,所以最后发布前的测试工作十分紧张。

统一测试的坏处在于,一方面,统一测试的工作量很大,面对一个初有体积的项目,要进行覆盖度较高的测试是十分耗时耗力的工作。另一方面,在最后统一测试的修复成本较高,在软件开发阶段发现并修正错误往往是比较容易的,但是当软件完成了整合,再进行测试并修正错误,那样的修复成本往往较高,因为在软件整合完成之后发现的BUG有可能是整合导致的,也有可能是某个组件自身带来的,这样不仅问题定位困难,而且修复时常常会涉及到多个组件,牵一发而动全身。

发布

在发布阶段,我学到的知识点是

推广十分重要,优秀的推广能够助力让产品最终拥有大量的用户

在alpha阶段的发布环节,我们团队并没有十分重视产品的推广,因而导致在alpha阶段最终用户数量不多,相应的,收到的用户反馈也就较少,为beta阶段的展开带来了一定的困难。

而在beta阶段,我们及早进行了发布和推广,有力地吸引了一批有效用户,他们为我们的项目提出了宝贵的意见和建议,从长远来看,这将十分有助于我们产品的进一步发展和更新。

维护

在维护阶段,我学到的知识点是

要做好系统数据收集工作,在维护阶段要密切关注系统数据记录,及时发现系统可能存在的问题

在alpha阶段,我们的后端系统并没有设计太多的日志系统,用户的操作基本都没有被有效记录下来,导致维护时出现了问题很难定位。

在beta阶段,我们针对后端系统的设计强化了系统日志方面的实现,记录了所有数据库查询操作、API访问操作等诸如此类操作的记录,便于在维护时定位错误和排查隐患。

四、理解与心得

无论是个人项目、结对项目还是团队项目,都需要有一个思路清晰的领导者(管理者)来把握整体的前进方向。

在个人项目中,自己是那个管理者,在结对项目中,两人都是管理者,而在团队项目中,PM是主导的管理者,每个人也都参与其中。

为什么说这个管理者十分重要,因为在多人完成一项任务时,思路统一是很重要的一件事情。每个人都有自己的主意,那样是无法拧成一股绳来合作的,需要有人来管理和协调,让大家的想法达成一致,才能使得团队高效地合作。

同时,管理团队和管理软件开发周期也是一门学问。

管理团队涉及到协调大家不同的意见,尽量不偏不坦,保证每个人的个性的同时又要保证团队的统一。要能够充分发挥每个人的特点,尽量满足每个人的爱好和想法,这本身就是一项十分有挑战的事情。

而管理软件开发周期更甚,软件开发涉及到多个环节,每个环节都有每个环节的任务和特点,在每个阶段都指定明确的目标对于按期完成软件开发而言有十分重要的意义。

同时,软件开发不仅是技术的挑战,也是设计的挑战。

高超的技术可以帮助程序员实现功能,但是并不能帮助程序员设计出优秀的产品。软件开发往往细节之处见真功夫,这种功夫不一定是实现难度有多高,往往是设计思想上的巧妙。优秀的设计可以让产品更加易用,更加具有粘性,让用户更加依赖于产品。

这一点我在我们的项目中深有体会。我们的IDE主打易用,所以在很多地方的设计上都是精雕细琢,如功能的布局、UI的设计、项目的入口等等,都力求让用户能够快速上手,长期使用。

此外,我也有一些想进行反思的地方。

首先是和大家的交流方式上,我觉得我一直存在一定的问题,同时,这也是团队合作中十分重要的地方。团队合作,大家不仅仅只是简单的在一起做个东西,人际层面的往来对团队的建设也十分重要,良好的交流方式有利于提高团队的凝聚力,营造良好的团队氛围。在这一点上,我觉得我做的还不够,有时会将个人情绪迁怒到他人,也是感谢大家对我的包容吧,能够让团队的合作一直很愉快。

还有就是缺乏思考,尤其是设计上的思考。好的软件开发人员会设计优秀的接口和服务,让使用者一看就能觉出这是大家之作,方便易用的同时功能全面。这一点上我觉得我做的还不够,很多时候都是功能有了就可以了,而不再进一步考虑如何优化接口,优化API设计,让调用者更加方便地使用接口与服务,这一点在未来的软件开发设计上也是需要提高的。

总结起来说,这一学期的软工实践体验是很充实的。从单人项目到结对项目再到最终的团队项目,实践了不同模式下的开发过程,也最终取得了一个小有规模的产品,无论是过程还是结果都值得欣慰。同时,通过一系列的实践,我也深刻体会到了团队大型软件开发的难度和痛点,也为将来的进一步学习和发展奠定了基础、明确了方向,从这些角度上讲,都是十分有益的。希望这个学期的实践可以成为未来软件开发生涯的一个好的开端。

posted @ 2020-06-16 19:46  _Nocturne  阅读(921)  评论(11编辑  收藏  举报