软工第一次阅读作业
软工第一次阅读作业
项目 | 内容 |
---|---|
这个作业属于哪个课程 | 2022春季软件工程(罗杰 任健) |
这个作业属于哪个课程 | 个人阅读作业 |
我在这个课程的目标是 | 学习软工的项目合作管理知识,提高团队开发软件的能力,积累项目管理经验 |
这个作业在哪个具体方面帮助我实现目标 | 通过《构建之法》了解软件工程的概念与流程,以及了解CI/CD领域并进行调研,从而了解如何进行竞品分析 |
关于《构建之法-现代软件工程》读后的若干疑惑
-
软件工程概论一节中:
在成熟的航空工业中,一个飞机发动机从构思到最后运行,不知道要经历过多少人, 多少工序,多少流程,多少相关知识的验证。我们无法想象,如果最后某个商用型号的发动机在飞行时发现问题,最初的设计师会自己爬到引擎中敲敲打打,然后钻出来说,“继续飞吧,我搞定了”。然而, 在软件行业中, 很多软件工程师往往以做这样的事而自豪。
这一段中,作者将航空工业与软件工程进行了类比,并指出两者之间在维护层次上的差异性。据我理解,作者的意图是指出维护软件对软件工程师来说是一件值得自豪的事情,因为这意味着软件可以不断迭代完善。但是显然,商用民航发动机应当对标的性命攸关的软件,而不是普通的商用软件。
《Code Complete》一书中曾提到商用系统是高度迭代的,这意味着允许错误是必要的。然而性命攸关系统,比如医疗系统和航天系统,是需要进行序列式开发的(正如航空发动机一样)。我很难不去怀疑,1996年Ariane 5火箭系统的最初设计者,在火箭爆炸后修复软件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的例子可能更能够说明的是,这种闹剧来自于团队的思考方式,而与过度依赖用户调研关系不大,因为这种团队会过度依赖一切可以量化乃至逻辑化的东西,不仅仅是用户调研。
-
软件工程师的誓言一节中,提到:
5.11 不要求软件工程师去做任何与道德规范相违背的事;
8.07. 不因为偏见而对任何人不公。
这一段,主要引发我思考的是最近的Ukraine冲突中,GitLab将图标换为蓝黄二色以表明对Ukraine的支持立场
当然,GitLab的开发者就是Ukraine人……
越来越多的事实表明,即使科学是无国界的,技术仍然是有国界的。我们暂且不讨论俄乌双方的道德立场,仅就这一个问题进行思考:“软件工程人员是否应该在其软件中掺杂偏见”。软件工程人员也是人,而人是允许持有偏见的(即使这并不提倡),但是是否应将这种偏见引入自己的软件中呢?
或许,处于商业和Politic的考量,软件公司应该可以决定是否对特定国家提供软件产品,这是无法避免的利益冲突与取舍。但是软件的构建过程是否应该成为International斗争的阵地呢?当我们将一串不友好的注释写在源代码里,在那一刻我们是否就失去了成为合格软件工程从业人员的资格呢?
对基于Git的源代码版本管理软件的调研
Git是第三代的分布式的版本管理系统,这意味着无需集中式的大型中心存储器,因此开发人员可以在不联网的情况下仍然在本地仓库中进行开发,然后在网络通畅时提交到远程仓库即可。
GitHub
GitHub是一个基于Git实现的在线代码仓库,是全球最大的代码托管平台,托管着许许多多优秀知名的项目,包括Spring、Vue等。目前处于微软旗下。
GitHub同时提供公有仓库和私有仓库,但是私有仓库需要进行一定的收费。鉴于开源项目的公开性以及GitHub本身巨大的用户数量,对于开源项目来说GitHub更具有吸引力。
GitLab
GitLab是一个用于仓库管理系统的开源软件项目,采用了Git作为代码管理工具。任何人都可以使用它搭建自己的在线代码仓库。
由于GitLab本质上是开源软件而不是第三方平台,因此对于企业开发团队来说,GitLab能够提供远比GitHub多得多的控制性。
Gitee
Gitee是国内对标GitHub的在线代码托管平台,在此基础上额外添加了许多功能,并在企业级的私有仓库开发上允许5人的小团队免费使用。
Gitee对国内通讯软件以及工作流软件的支持更好,提供了一些更加企业向和产业向的管理功能。但是用户群体显然较小,而且促销广告多,社区版包含大量与代码开发无关的内容。
开发流程
三者在核心功能上基本一致,这也导致其基本的工作开发流程大同小异,接下来以GitHub为例介绍我所理解的开发流程:
- 建立开发分支(比如dev)
- 开发人员Fork项目到个人账户下
- Clone到本地后进行开发
- 每次修改文件前Fetch一下远程仓库保证文件一致
- 将本地修改Push到个人账户的对应仓库下
- 向团队项目发出Pull Request
- 团队负责人审核并同意Pull Request,相关修改正式进行Merge
调研CI/CD工具
持续集成(Continuous Integration, CI)是指代码提交后在并入主分支前进行一系列测试与构建,从而降低引入BUG的概率。
持续部署(Continuous Delivery, CD)则是在CI的基础上更进一步,将推送的分支部署到产品环境中,实现持续的产品交付。
热门的CI/CD工具
Jenkins
Jenkins是CI/CD领域最早最大的开源CI工具,是整个CI/CD领域的事实标准。正因为其长久的生命力,使得其插件市场极为丰富,并且提供了多种扩展版本的Jenkins,比如JenkinsX等。因此Jenkins可以免费地满足几乎所有CI/CD需求,允许从Git或SVN等多种VCS上拉取代码,但是代价是更加高昂的学习开销和更为繁琐的日常使用。
Travis CI
Travis CI是一款软件即服务(SaaS)的CI系统,可以绑定在GitHub或Bitbucket的项目上,然后直接访问Travis CI的网站进行项目的持续集成,而不用自己来进行部署。这使得其更加方便的同时,也使其更加不可定制化,因此在企业应用中份额较少。
GitLab CI
GitLab CI的一大特点在于其免费开源且定制性强。其中引入了Runner概念,使得使用者可以自定义用于持续集成部署的机器,进而提供了更高的可定制性,深受企业用户的青睐。
GitLab CI内置在GitLab中,需要在仓库根目录下创建.gitlab-ci.yml
文件,然后配置一个GitLab Runner用于执行.yml
脚本。每次提交,GitLab会自动识别.yml
文件然后使用Runner运行它。
在GitLab CI中,每个提交触发的行为集合称为Pipeline,每个Pipeline包含多个stage,stage对应job,而job下包含script用于描述具体执行的命令。
GitHub Action
GitHub Action中将CI/CD的操作内容称为Action,并且认为在不同的项目中,这种Action是极为类似的,因此允许开发者将Action写作独立脚本文件,从而让其他开发者引用,这极大地方便了社区用户编写CI/CD脚本。
开发者需要在.github/workflows/
目录下存放.yml
格式的文件,然后在文件中写明如何执行workflow。每个workflow都会在提交时被执行,主要包括触发条件(on)和行为(job),每个job包含多个step,每个step包含多条Action,并且可以通过use关键字引用外部Action。
Gitee Go
Gitee Go采用了Pipeline来描述它的构建过程,同时提供了制品库管理、主机管理等附属功能,使得整个CI/CD流程更加完善,提供了一条龙服务,但是其Gitee Go需要付费使用。
Gitee Go最让我影响深刻的是其非常友好的图形视图,可以清晰地查看和设置CI/CD的各个步骤与流程,每个流程对应一个脚本。Gitee Go提供了类似Github Action的预设定脚本来处理特定的情景,但是不是社区化的,而是Gitee给定的。
我进一步查看其代码视图的脚本格式,可以发现其结构基本和Github Action的一致,这降低了迁移学习的成本,但是也让我怀疑Gitee Go只单纯是Github Action的付费仿品。Gitee Go在国内这一大环境下一定程度上填补了Github留下的空白。
解决方案对比总结
解决方案 | Jenkins | Travis CI | GitLab CI | GitHub Action | Gitee Go |
---|---|---|---|---|---|
是否收费 | 否 | 否 | 否(社区版即可支持) | 否 | 是 |
可定制化程度 | 很高 | 很低 | 中等 | 较高 | 较低 |
图形界面的使用体验 | 功能丰富(插件支持) | 较单调,倚重代码 | 较单调,倚重代码 | 较单调,倚重代码 | 支持无代码操作 |
是否能提供一条龙服务 | 可以(插件支持) | 仅CI/CD内容 | 可以(支持Runner定制) | 仅CI/CD内容 | 可以(辅助功能) |
使用体验是否便捷 | 繁琐 | 简单(软件即服务) | 繁琐(需要部署) | 简单(支持复用Action) | 简单方便 |
预计的用户群体 | Geek开发者和团队 | 个人开发者 | IT企业开发团队 | 个人开源开发者 | 中国的个人开发者和非IT企业团队 |
解决方案一:采用Gitee Go实现对Flask Web后端的测试
基于Gitee Go对原来数据库大作业的Flask后端进行在线测试
使用Gitee Go的图形化界面进行低代码开发,主要测试了其随机数生成模块:
触发脚本后,得到Gitee Go构建结果:
解决方案二:采用Github Action与Hexo的静态博客自动编译部署
基于Github Action对自己的静态博客进行持续部署。
Hexo是静态的框架,因此如果不使用CI/CD的情况下,需要手动构建和部署。
现在的解决方案是,采用一个项目A作为Hexo项目,然后利用Github Action进行自动构建与部署,然后自动部署到Github Page对应项目B中,免去了本地构建的麻烦。注意这里项目A不是github.io项目,而是专用于存储文档的。项目B才是github.io项目,可以视作部署环境。
我首先在项目A中编写自动构建和部署代码,如下:
然后当我新建一个.md
笔记并push到项目A时,就会触发CI/CD脚本进行自动构建,并将构建完成的项目部署到项目B中:
由于部署的本质也是push,项目B因此也会触发其上挂载的GitHub Page部署脚本,进而将Web服务构建完成并发布: