软工——浅谈“构建之法”
问题 | 内容 |
---|---|
这个作业属于哪个课程 | 2021春季计算机学院软件工程(罗杰 任健) |
这个作业的要求在哪里 | 个人阅读作业2要求 |
我在这个课程的目标是 | 提高个人开发水平以及团队合作意识 |
这个作业在哪个具体方面帮助我实现目标 | 阅读《构建之法》了解课程目标 调研源代码版本管理软件和持续集成/部署工具 |
读书小结
在看到《构建之法》的书名时,我以为会是一本讲系统架构的技术书籍,但后来翻阅的时候发现并非如此。我阅读的是第三版,相对于前两版,作者删减了不少章节,反而重点叙述了很多软件工程中的实战内容。虽然我个人暂时没有参与过大型软件项目的工作,但是在读到很多章节时却能奇妙地产生一些共鸣。该书沿用了《移山之道》中的一些人物,包括大学生、研究生或者刚工作几年的技术人员,通过人物之间的对话和活动生动形象地还原了软件开发中可能出现的场景,这也是这本书让读者觉得更加真实熟悉的原因。
由于时间原因我并没有完整的看完此书,只是选择性地进行翻阅,也希望自己在日后的学习工作中遇到疑惑时再回头翻阅这本书能有更深刻的体会和更大的收获吧。
阅读提问
1、结对编程是否有大规模应用的可能
在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。
在结对编程中,任何一段代码都至少被两双眼睛看过,被两个脑袋思考过。代码被不断地复审,这样可以避免牛仔式的编程。(《构建之法》4.5.2)
就软件工程这门课来说,结对编程可能是从锻炼大家与他人的沟通交流以及合作开发的能力出发进而开设的项目。但是从行业整体来看,结对编程似乎并没有进行广泛应用。文中提到“程序质量取决于一对程序员中各方面水平较高的那一位”以及“结对编程迫使程序员必须频繁交流,而且要提高自己的技术能力,以免被人小看”。虽然由这种假设所推导出的结论是美好的,但是我个人认为这里的假设有些过于理想化。
- 在现实中公司以“结对编程”的形式迫使员工提高个人技术能力未免显得成本有些过于高昂,甚至在两人水平差距过大的极端情况下可能出现一方始终在学习而另一方始终在工作的状态。
- 如果双方水平差不多,结对的效果与一方写完代码后另一方进行测试的团队模式好像没有明显区别。这样看来未免有些为了结对而结对的意味。
其次“代码”被不断地复审虽然会使最终代码的质量有所保证,但是除非是一个紧急项目,否则所花的人力与时间成本应该是远远大于后期测试成本的。在结对编程与两人合作博客中举了很多互联网技术的重大突破都是由两人完成的实例,但是如果仔细研读就会发现并不是所有人都适合结对编程,换句话说,这些人的成功跟他们自身的特性密切相关。或者两人所学专业恰好互补且在各自的领域都有很深的造诣,或者合作时间很长并且坚持相同的信念等等。如果没有这些偶然,结对编程对我们日后的发展是否有很大的借鉴意义呢?
2、单元测试是否一定要程序员自己编写
软件的很多错误都来源于程序员对模块功能的误解、疏忽或不了解模块的变化。如何能让自己负责的模块功能定义尽量明确,模块内部的改变不会影响其他模块,而且模块的质量能得到稳定的、量化的保证?单元测试就是一个很有效的解决方案。(《构建之法》2.1)
单元测试必须由最熟悉代码的人(程序的作者)来写。(《构建之法》2.1.2)
前文中说道“软件的很多错误都来源于程序员对模块功能的误解、疏忽或不了解模块的变化”,说明很多错误是由于程序员的个人原因造成的,甚至自己都没有意识到相关模块的错误。就个人而言,做测试时我只会测试自己考虑到的情况,与写程序时自己的思路不会有太大改变,当时没发现的错误测试时由于逻辑漏洞也很难发现。所以即使自己很熟悉代码,但是因为思维惯性就很难跳出自己设的陷阱,如果换别人反而可能在更短的时间内找出bug。
在很多设计课程中,同学们可能会相互分享测试数据增强自己程序的鲁棒性。这里先将自动生成单元测试排除在外,如果仅靠大家自己测试可能很难发现自己程序的漏洞,但是我们又往往能在他人提供的数据中能发现错误。况且单元测试一般只是测试一个程序的部分功能,与对程序的熟悉程度没有太大关联,所以,如果程序员自己有时间当然可以编写测试程序,如果没有时间也可以通过文档描述自己程序哪些地方思路不太完善让测试人员做重点测试应该也不失为一种可行的办法?
3、测试人员的要求
阿超:一个商业项目,请不要让连开发语言都没有接触过的队员进行开发工作。并不是非得“写”程序才是对项目有贡献,有时不写也有很好的贡献。如果他们有热情,就从测试开始学习吧。(《构建之法》11.8)
阿超:开发人员的代码没写好,可以依赖于测试人员来发现问题。但是如果测试人员的代码没写好,我们依赖谁来测试和改错呢?这就要求我们测试人员的代码质量特别高,因为测试人员是最后一道防线,如果我们的代码和测试工作有漏洞,那么Bug就会跑到用户那里去。(《构建之法》13.3.1)
让“连开发语言都没有接触过的队员”不要进行开发工作说明了写程序这一步骤在项目中的重要地位,这当然是无可厚非的,但是让他们从测试开始学习是否就说明测试工作允许犯错的几率更大呢?那后文中的“测试人员是最后一道防线”说明项目对测试人员的代码质量要求也很高,而且测试人员要对他人的代码应该需要很强的洞察力,这也是建立在自己强大的编程和逻辑基础之上的。我们不愿意让小白担任开发又怎么能愿意让他做与客户连接的最后一道防线呢?
诚然无论是测试还是开发,如果能写出高质量代码当然最好,但是如果没有过硬的技术又更适合担任哪一类职务呢?测试人员的硬性标准又该是什么呢?
4、最成功的创新是在拿手领域之外发现的?
我们不就是为了成为某个领域的专家,才来上学,拿学位,希望拿到学位之后成为专家,然后再开始这个领域的创新?但是统计数据表明,70%的创新者说,他们最成功的创新,是在他们的拿手领域之外发现的。(《构建之法》16.1.5)
对这个观点我不太认同。什么叫“拿手领域”呢?因为阿里巴巴的创始人马云本科本科毕业于杭州师范学院外语系,所以我们认为他的拿手领域是外语吗?从马云的早年经历看似乎并非如此:1994年马云与来自西雅图的外教聊互联网并开始寻找机会创业,1995年他去了西雅图第一个ISP公司VBN参观,同年3月他从学院辞职,同年4月,中国黄页正式上线。到1999年,马云团队回到杭州又开始了新一轮创业,开发阿里巴巴网站。在此过程中,我们可以认为马云抓住了时代的机遇,但我们并不能认为互联网不是他的拿手领域,即使他不是科班出生,但他为此付出的努力以及最终的成就足以说明他的确“拿手”。
特定领域的教育的确能大大提升我们某一方面的专业素养,但与此同时各个领域之间并非界限分明。当今很多行业需要多领域人才融合发展,就如同互联网行业光靠本专业的技术人才是远远不够的,需要有一些架构人物帮助推动行业的整体发展,跟拿不拿手以及所学专业无关。
5、关于用户体验的惯性
用户在网上提交信息,通常会看到两个相邻的按钮,【提交】【取消】,这样简单的设计仍有很多可以改进的地方,例如有下面的建议。(《构建之法》12.1.5)
关于提高用户体验方面,该书提到了例如可以将意义相反的选项间隔拉大或者采取不同的样式,降低用户误操作的可能性,这是一种简便但不失有效的方法。但与此同时,我想用户为什么会误操作呢?比如在我们个人电脑上有时会出现一些广告弹窗,我们会习惯性地点击右上方关闭,但往往这里的按键会把广告直接打开,后来费了很大力气把它关掉后发现真正的关闭键设置在弹窗的左上方。
当我们习惯使用某个功能后往往会产生一定的思维惯性,如果被一些人加以利用,即使没有太大损失,也会对我们使用产品的流畅性造成较大的困扰,这里又该如何避免呢?是否需要上升到制定一些行业规范的高度来控制此类行为呢?
6、创新者困境
如果公司不断满足已有用户需求,则产品在趋于饱和的市场缓慢发展,在产品的生命周期结束后,不免会被新的颠覆性创新淘汰;如果公司主动寻找颠覆性创新,则遭到公司内部流程、价值观和文化的排斥(《构建之法》16.1.7)
文中提到“颠覆性的创新会带来产品和市场的巨大风险,这些企业中的流程、价值观和文化会排斥颠覆性的创新”。的确颠覆性的创新会有巨大风险,后文中也举例说明了这一观点,但是成功的企业之所以成功就是因为当年的颠覆性创新,当市场成熟后,成功的公司一定会主动寻找新的创新点,而不是坐以待毙。更何况成熟的公司已经具有雄厚的资金和人脉,在创新产品后有更便捷的推广渠道,也能承受相关的一些风险。而一些小公司虽然可能带有颠覆性创新,但是在产品推广的第一步可能就困难重重,一旦某个环节出现差错可能整个公司都完蛋。
我们现在看到一些成功的小公司都是在层层筛选下运气和机遇都恰到好处的公司,那些创业失败的案例我们又能接触到多少呢?成功企业的创新可能性是否应该比小企业要大些呢?
7、关于极限编程
所谓极限编程,就是把一些认为重要和有效的做法发挥到极致。(《构建之法》6.4.1)
我对于表格中部分发挥到极致的做法有些困惑。左栏中的做法看起来都是重要且有效的,但是到了极致似乎就有些“偏离正道”。
- 每时每刻都有客户在身边——首先这条件似乎比较难以实现,其次虽然客户需求在实时变化但如果事先不尽量细致了解客户总体要求就可能会需要连续重构,放在课程中可以锻炼我们的编程能力,放在工作中恐怕就不太合适了,会增加大量的时间和人力成本。
- 别做详细的设计,做频繁的增量开发、重构和频繁地发布——与上文类似,即使计划没有变化快,但这是否就意味着我们可以没有计划呢?频繁地发布所耗的资源与做详细的设计耗费的资源哪一个更多呢?
调研源代码版本管理软件
关于GitHub、Gitlab、Bitbucket等源代码版本管理软件的异同:
相同点(基础特点):
- 拉取请求
- 代码审查
- Markdown支持
- 高级权限管理
- Fork / Clone Repositories
- 第三方集成
不同点:
- GitHub:开源协作的首选。目前GitHub上拥有全世界最大数量的公共开源项目,全球顶级科技公司(Google / Apple / Facebook 等)都加入GitHub,全球顶级开源项目(Linux / Nodejs / Swift 等)都优先选择在GitHub上开源。
- 关于导入的代码仓库类型不同:GitHub支持导入Git,SVN,HG,TFS. GitLab支持导入Git,而Bitbucket支持导入Git,CodePlex,Google Code,HG,SourceForge和SVN。
- 关于免费计划:虽然三家服务商都提供免费计划,但是还是有一些差异。GitHub的Free Plans允许托管无线的公有代码仓库,随时进行clone,fork和contribute,对磁盘使用没有限制,但是项目不能超过1GB和单个文件不能超过100MB;Bitbucket的Small team plan允许5个成员加入,公有/私有仓库军免费,当项目快到达1GB时会有邮件通知;GitLab的cloud-hosted plan允许无限数量的用户在无限数量的公共和私有项目上进行协作,并且没有存储库有10GB的空间限制。
调研持续集成/部署工具
Gitlab CI
- 这里使用 oo-2020-pre3task1 的内容,首先在本地用 maven 重新创建项目,再进行简单的JUnit4测试:
- 配置Gitlab CI,并进行在线测试和运行(相关Gitlab仓库在这里):
- 可以在Jobs的status里面看到持续集成所有命令输出的结果:
GitHub Actions
-
这里使用的文件与 Gitlab 相同,但是需要将 .gitlab-ci.yml 替换成 .github/workflows/.yml
(具体代码仓库在这里)
- 根据文档编写 yml 文件,触发action编译运行:
- 点开 jobs 可以看到每步执行情况:
关于对CI /CD 工具使用后的看法
首先 CI / CD 是包括持续集成(Continuous Integration)、持续交付(Continuous Delivery)和持续部署(Continuous Deployment)的新方法。持续集成的重点是将各个开发人员的工作集合到一个代码仓库中,主要目的是尽早发现集成错误;持续交付的目的是最小化部署或释放过程中固有的摩擦;持续部署是一种更高程度的自动化,无论何时对代码进行重大更改,都会自动进行构建/部署。这些阶段中的每一个都是交付管道的一部分 。
我所使用的CI和CD工具的特点特性描述:
- Gitlab CI 的触发为 Git 提交检索 .gitlab-ci.yaml 文件触发,其免去了第三方 CI 服务器对利用 webhook 定时请求 Gitlab 的压力。本身设计为 Config as Code 将CI / CD 配置托管在项目中,避免每个人手工配置的 CI 或还有不一致带来的问题。真正的架构为 C/S 架构模式,可方面的进行横向扩展,运行 job 性能上不会有影响。其CI过程利用gitlab自带的邮件通知,不用额外配置通知。
- Github Action 是Github官方推出的一款 CI 工具。由于 CI 由很多操作组成,比如抓取代码、运行测试、登录远程服务器、发布到第三方服务等等,Github把这些操作成为 actions。GitHub 允许开发者把每个操作写成独立的脚本文件,存放到代码仓库,使得其他开发者可以引用。如果我需要某个 action,不必自己写复杂的脚本,直接引用他人写好的 action 即可,整个持续集成过程,就变成了一个 actions 的组合。这就是 GitHub Actions 最特别的地方。GitHub 做了一个官方市场,可以搜索到他人提交的 actions。
- 关于 Gitlab CI 与 Github Action 的详细区别参考该网址,以下列出了几个个人认为对使用体验影响较大的方面:
比较方面 Github Action Marketplace NO YES Support for CD-Built in and not third party CI/CD fully integrated - no 3rd party Plugins/tools need Auto CI/CD Pipeline Configuration - 就个人当前的使用体验而言,两种持续集成工具界面都比较直观,但Github Action可以自动生成 yml 文件模板或者在 marketplace 中找到他人的 Actions ,大大节省了开发者的时间,并且Github上开源项目的优势也是极其明显的。