软件工程-个人作业-提问回顾与个人总结

对曾经的问题进行解答

以前提问题的博客

软件工程概论一节中:

在成熟的航空工业中,一个飞机发动机从构思到最后运行,不知道要经历过多少人, 多少工序,多少流程,多少相关知识的验证。我们无法想象,如果最后某个商用型号的发动机在飞行时发现问题,最初的设计师会自己爬到引擎中敲敲打打,然后钻出来说,“继续飞吧,我搞定了”。然而, 在软件行业中, 很多软件工程师往往以做这样的事而自豪。

这一段中,作者将航空工业与软件工程进行了类比,并指出两者之间在维护层次上的差异性。据我理解,作者的意图是指出维护软件对软件工程师来说是一件值得自豪的事情,因为这意味着软件可以不断迭代完善。但是显然,商用民航发动机应当对标的性命攸关的软件,而不是普通的商用软件。

《Code Complete》一书中曾提到商用系统是高度迭代的,这意味着允许错误是必要的。然而性命攸关系统,比如医疗系统和航天系统,是需要进行序列式开发的(正如航空发动机一样)。我很难不去怀疑,1996年Ariane 5火箭系统的最初设计者,在火箭爆炸后修复软件BUG时,会感到的是自豪还是自责。

在我自己实际参与的软件开发过程中,团队经常要发现并修复BUG,这是不可避免的。但是,请注意非常重要的一点,测试阶段与发布阶段是截然不同的。我们所说的“发现BUG并修复”如果发生在测试期间,那么这属于一个软件工程师的正常期望范围,“我们期待着BUG的发生并修复它”,因此软件工程师确实会因此而自豪,因为ta能够真正地发现BUG并在交付前修复它。但是,如果BUG发生在生产期间,当软件真正地交付给了用户之后,任何一个软件工程师都不会期望用户拿着人员财产损失报告来找自己算账。

工程师的能力评估和发展一节中:

软件设计工程师们在做代码复审的时候,是看“重复字”的多少, 还是程序的艺术性?

这一段中,作者将编程与艺术进行对比,来引发我们对创造性和规范性之间的思考。据我理解,“避免重复字”可以视作诗歌创作的一条规范,而违背这一规范并不影响诗歌的艺术性。

我们不妨去思考,规范是如何产生的?这里我也像前一章节一样引用民航业作为例子。民航爱好者都知道,“航空法规是用血与生命换来的”,每一条条例的背后都可能是一场无比惨烈的空难。911后,美国的很多机场才开始重视机场安检。

回到文中的例子。苏东坡的诗歌违反了重字规范,但是并没有影响他的艺术性。但是当我们放眼历史时,总能看到那些因为违反重字规范而显得无聊枯燥的诗歌。如果我们看到一趟没有进行安检的航班顺利完成它的旅程,就片面地认为遵守规范并没有意义,那么总有一天会面临911那样的灭顶之灾。

对于软件来说,我认为也是一样的。遵守规范或许不会总是有用,但是抛弃规范而追求艺术性,总是要承担更高的不可预料的风险。我的困惑是,在实际软件工程中,我们如何去评估追求艺术性带来的风险呢?以及如何依据评估结果来制定规范?

在我自己实际参与的软件开发过程中,我们采用静态检查工具来对团队的代码规范进行检查。我们默认,任何符合静态检查规范的代码都是合格的,而在这个大框架内追求艺术性是被允许的,也就是规范性优先于艺术性。这是因为我们必须明白,对规范性进行检查永远比对艺术性进行检查更加方便。而至于评估艺术性会导致的风险,我认为是不应该考虑的。我的想法是,艺术性本身是因人而异的,而团队本身是需要统一性的,因此我们应该避免在团队事务中讨论艺术性的价值与风险。不过,仅就规范性而言,也存在有多套不同的成熟的方案,它们就像不同国家的汽车一样,它们之间的异同有其内在的历史原因,但是都能很好地完成优化团队开发流程的任务。

技能的反面一节中:

那怎么提高技能呢? 答案很简单, 通过不断的练习, 把那些低层次的问题都解决了, 变成不用经过大脑的自动操作, 然后才有时间和脑力来解决较高层次的问题。

这一段中,作者指出技能的反面是过于着重于具体地解决低层次问题。

我的疑惑在于,我们如何区分高层次与低层次。文中作者指出,“需要花费脑力解决”是更高层次问题的一个关键特征,而可以通过自动化的熟练度来解决的问题通常是是一个低层次的问题。

但是显然,当我们经常思考一类问题时,下一次遇到类似问题我们其实也可以仿佛直觉般不经思考得出答案,那么这种行为是否模糊了高层次与低层次之间的界限?以数学为例,掌握和使用基本积分公式可以视作低层次的行为,而使用公式解决复杂积分问题可以视作高层次问题,但是熟练的数学竞赛同学完全可以不经思考地对复杂积分问题进行分解,那么此时如何定义层次呢?

我的疑惑是,是否针对不同的人而有不同的高低层次的判断标准呢?根据人的认知程度不同,“技能”这一概念是否也有不同?

在我自己实际参与的软件开发过程中,很多时候我们会采取成熟的方案,比如采用中间件、建立路由守卫、用户鉴权模块……什么时候使用这些方案?如何使用这些方案?这看似是一个高层次的决策性问题,但是实质上需要通过大量试错和项目经验的,而我认为其是一个高层次问题。“需要花费脑力解决”中的“脑力”,不仅是指解决该问题时付出的脑力代价,而且也包含了曾经为了解决相似问题而积攒的经验与教训。对于不同的人,他们的天赋其实差不多,真正有所差异的是他们的经历与经验,而如果我们将“经验”作为“曾经付出的脑力代价”计入考虑范围,就会发现对于不同的人,也能有统一的高低层次判断标准

软件的质量保证和测试中,提到:

即使你的软件产品功能100% 符合spec 的要求,但是用户也可能非常恨你的软件。这时,测试人员就没有尽到责任,因为测试人员要从用户的角度出发,测试软件。

这一段中,作者反对了测试人员机械地对着规格说明书进行测试这一现象。引起我疑惑的是“测试人员需要从用户的角度出发测试软件”这一点。

根据我的了解,测试人员在很多软件团队中处于一个尴尬的位置。大部分公司甚至没有专门的测试人员,而让开发人员兼职。因此,很多时候即使是专业的测试人员,其素质水平和能力也不尽如人意。同时,我还参考了各大招聘网站对测试工程师这一岗位的要求以及面试情况,通常都集中于测试方法的了解和使用以及工作经验上,而鲜有“面向用户进行测试”的要求。

因此,“面向用户进行测试”的能力对于团队中的测试人员来说是否是必须的呢?一个懂得用户体验的测试人员对于团队来说是否冗余呢?(尤其当团队已经存在对用户需求进行分析的专职人员时)。

在我自己实际参与的软件开发过程中,测试是一件非常复杂的事项。我们不仅要对接口进行完全的测试来实现较高的代码覆盖率,也要从用户的角度去真正使用并检查各种功能。这种现象在前端开发中体现得更加显著,因为前端的性质就决定了我们必须从用户的视角出发去进行测试。这个按钮要不要加动效?这个字号是不是太小了?这个按钮怎么没有反应?……用户体验是前端测试中非常重要的一点。如果枉顾用户体验而片面追求功能性的测试,那么你开发出来的软件虽然各项功能都可以正常使用,但是用户也会非常恨你那糟糕的用户体验

用户调研一节中,提到了一个有趣的问题:

当你的公司要你用数据来证明 41 种蓝色到底哪一种更好, 或者为一个边栏宽度是3, 4, 或5 而争执不休, 纷纷表示要拿数据来证明的时候, 你怎么办?

这一段中,作者引用了Google视觉设计主管Douglas Bowman的一段经历来发出这个问题,从而说明过度强调用户调研带来的问题。引起我的困惑的是,为什么Google这么一家理应如此精通此道的公司,会在这么一个问题上犯如此明显的错误?

当这段问题被单独提出来时,显然任何一个开发人员都会觉得好笑。那么当时参与这场争执的工作人员难道不会意识到如此引人发笑的问题的存在吗?问题究竟出在哪里?

我通过调研求证了上述这一例子,并找到了出处——Douglas Bowman离开谷歌时的文章Goodbye, Google 。文中他提到,在他开始掌管视觉设计团队时,Google的视觉设计人员都是一批精通工程却从未真正领导过视觉设计的科班人才。Douglas指出"When a company is filled with engineers, it turns to engineering to solve problems",这使得任何问题最终都转变为逻辑问题,并最终导致了这种令人哭笑不得的问题。

因此,我觉得这里引用Douglas的例子可能更能够说明的是,这种闹剧来自于团队的思考方式,而与过度依赖用户调研关系不大,因为这种团队会过度依赖一切可以量化乃至逻辑化的东西,不仅仅是用户调研。

在我与PM的讨论中,我们谈到了如何来统一团队的一些决策。我认为团队需要一定的“独裁性”,将某些低优先级事务的最终决策权交于一位最有经验的编程人员。因为有些琐碎的问题不仅很难在团队内统一意见,也会引发团队内不必要的矛盾,甚至还可能成为团队内小团体勾心斗角的战场。避免不必要的冲突与矛盾,是我认为团队管理中非常重要的一点

软件工程师的誓言一节中,提到:

5.11 不要求软件工程师去做任何与道德规范相违背的事;

8.07. 不因为偏见而对任何人不公。

这一段,主要引发我思考的是最近的Ukraine冲突中,GitLab将图标换为蓝黄二色以表明对Ukraine的支持立场

当然,GitLab的开发者就是Ukraine人……

越来越多的事实表明,即使科学是无国界的,技术仍然是有国界的。我们暂且不讨论俄乌双方的道德立场,仅就这一个问题进行思考:“软件工程人员是否应该在其软件中掺杂偏见”。软件工程人员也是人,而人是允许持有偏见的(即使这并不提倡),但是是否应将这种偏见引入自己的软件中呢?

或许,处于商业和Politic的考量,软件公司应该可以决定是否对特定国家提供软件产品,这是无法避免的利益冲突与取舍。但是软件的构建过程是否应该成为International斗争的阵地呢?当我们将一串不友好的注释写在源代码里,在那一刻我们是否就失去了成为合格软件工程从业人员的资格呢?

我无意间在TensorFlow上看到有一个帖子讨论了这个问题。软件就像是一个人撰写的文章,而自古以来,无论中外,文字都是意识形态的体现。即使再多的人坚持“书生不论政治”,也无法否认文字在历史上扮演了意识形态传播者的角色,我们也不会认为一个在作品中输出了意识形态的艺术工作者不是一个合格的艺术工作者。

每个阶段的知识点

需求

典型用户与故事。设置几种典型的用户角色,并将自己代入用户角色的视角来考虑需求。事实上的关键在于如何选择需要设置的角色以及如何更好地代入角色的视角。为了实现前者,通常会依赖于专业的市场分析人员给出角色的类型及其比重。为了实现后者,通常会通过为角色命名以及撰写背景故事来提高角色的真实性,从而加深需求分析人员的共情感。

设计

图形化建模分析。通过图形化的方式对事物进行建模,能够很好地体现出事物之间的联系,让软件开发人员能够在后续时刻准确把握设计的内容。图形化建模主要包括思维导图、关系图、数据流图、时序图等等,需要根据不同的需求选择不同的建模方式。从文档的角度来说,优秀的配图是一份优秀文档的关键。

实现

进度管理。如何科学地推进项目的实现进度是一件非常艰巨的任务,不仅需要依赖于正确的工具,还要依赖于正确的方法。在工具上,我们选用了Notion作为平台,统一管理文档与项目进度表格,对于每个需要实现的模块设置了状态与完成时间,并且支持链接到某个文档。在方法上,我们采用Scrum Meeting的方式,及时交流信息与讨论遇到的问题,极大地助力了团队的有序推进。

测试

测试矩阵。测试是一个非常重要且复杂的工程,我们应该测试哪些功能?应该测试到什么层次?应该在什么环境下测试?决定“一个测试是什么”的因素维度比较多,这也导致我们很难去定义它。测试矩阵给予了我们一个二维的模型来定位我们的“一次测试”,我们可以将两个维度分别定义为测试场景与测试功能,也可以定义为测试层次与测试功能。矩阵的两个维度虽然无法完全定义“一个测试”的复杂性,但是足够让我们在实际工作中对不同的测试进行有效的区分与归类。

发布

** 有序冻结**。伴随着程序的功能逐步完善以及BUG的逐步减少,需要将程序的各个部分有序地“冻结”,也就是不再进行随意的修改(通常来说并不是完全拒绝修改,而是设置非常高的修改门槛)。在前后端逻辑上,我们首先会冻结基本的页面逻辑,然后冻结页面样式,之后逐步冻结整个前端,只对后端的代码开放修改,以保证用户体验的一致性。在功能上,我们会逐步冻结一些已经全面测试过的功能,将其签入成品分支中,并将其设置为基础版本,后续开发将基于该基础版本继续开发。

维护

结构化维护。采用规范的结构化思想来进行代码维护,首先应该在抽象的设计层面进行修改,论证修改的有效性与可行性,之后从当前成品分支切出新的分支来进行源代码编写与验证,然后需要根据之前的测试文档进行回归测试来保证没有引入新的BUG,最后通过代码审查并签入成品分支。结构化维护的根本主要完善的文档与版本管理,这对项目管理提出了很高要求。

心得体会

软件工程课程终于结束了,这一个学期以来,多少个日日夜夜里,我们都在开发的路上蹒跚前行。我知道,通过艰苦的实践与开发,我们比同龄的大多数人都更加疲惫,也比同龄的大多数人都更加了解了软件工程的意义。

开发就像是走一段长长的路,有朋友们陪伴总是会轻松很多。在开发过程中,我与伙伴们相互扶持,共同进步,分享与讨论我们遇到的技术问题,也互相调侃彼此编码时犯下的的低级错误,这让我们能够一路坚定地走完这一趟。

我在团队中负责了前端的开发。在技术层面,我接触了很多新鲜的技术与想法,而这都是我从伙伴们那里得到的灵感。同时我也通过不断的试错,在项目开发的过程中不断修改技术方案,探索出了自己的一套技术方法,提高了自己的编程能力。而我觉得最重要的是,软件工程让我真正感受到了团队协作的氛围,如何建立更加有效的交流方式?如何依赖工具与科学方法来提高交流的效率?这都是我在其他地方所不会遇到的问题,但是软件工程的实践让我对此有了自己的答案。

posted @ 2022-06-20 10:58  neumy  阅读(89)  评论(0编辑  收藏  举报