0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Google软件工程中主要的过程部分

Linux阅码场 来源:Linux阅码场 作者:Linux阅码场 2022-09-23 11:50 次阅读

上篇[1]介绍了Google软件工程中的文化部分,本篇介绍软件工程中主要的过程部分,包括编码风格指南、代码评审、技术文档、自动化测试(单元测试、集成测试与较大型测试)与弃用。

以下是《Software Engineering at Google》一书第三部分过程篇的思维导图,由于此部分占全书近40%,所以本文不会详细的介绍其中的概念,想详细了解的读者建议阅读原书。本文会结合此书这部分内容分享作者的个人理解及相关经验。

5477e760-3ad6-11ed-9e49-dac502259ad0.jpg

风格指南(Style Guide)

We value “simple to read" over "simple to write." (Software Engineering at Google - Style Guides and Rules)

代码可能只会被写一次,但会被读很多次。如果团队成员的代码风格都不统一,可读性会很差,所以保持团队代码风格统一很重要。

历史证明,能写的很飘逸的编程语言使用人数一般都不会很多,典型的如古老的Perl语言,可以达到“一人千面”的代码风格。而写起来中规中矩甚至没有啥高级技巧的语言如Java、Go等在工业上反而用的很多。

Google的代码风格指南不太适合一般规模的公司,所以此部分不做过多介绍。从我的个人经验来说,一般项目上会配置一套自动化的代码风格检查工具(如checkstyle[2]),甚至会集成到流水线(Pipeline)中强制团队保持一致的代码风格。某些编程语言如Go在构建工具中也提供了gofmt的代码格式化工具。

代码风格指南只能解决一些很基本的可读性问题,如代码缩进、函数命名风格、代码行数限制等。但代码的可读性可不只体现在这些表面,更深层次的可读性问题如API语义的可读性该怎么解决?一个可行的实践是代码评审。

代码评审(Code Review)

代码评审是如此重要,以至于其在Google是必须做的一个实践过程。它能提供以下的好处:

•代码正确性:评审人员可能发现评审代码中的逻辑问题,从而提前消除一些潜在的Bug;•代码可读性:代码能否被其他人很容易的理解?API语义设计是否合理?是否包含测试?是否有必要的文档与注释?•代码一致性:代码风格是否与团队和组织保持一致?•促进团队知识共享:代码评审可以让团队其他成员了解你所做工作的上下文;•塑造团队工程文化:团队保持代码评审的实践,本身也是团队工程文化的一部分,能让新的成员迅速适应团队工程文化;

代码评审的最佳实践有以下:

•友善且专业•小的变更•清晰的变更描述•小规模评审•尽可能自动化•金字塔模型

代码评审金字塔模型如下图所示:

5539c088-3ad6-11ed-9e49-dac502259ad0.png

代码评审的反模式是倒金字塔模型,也就是很多时间花费在了可以自动化执行的部分比如代码风格的统一、自动化测试等,但在金字塔模型里,代码评审应该把主要的精力放在API语义、实现语义及文档等部分。

Code Review v.s. Code Diff

Diff 和 Review 的区别在于前者是一个团队集体行动,团队成员一块看某个开发者前一天写的代码,这样的好处在于每个人都能反馈,也能了解其他人做的工作,防止一些信息不同步的问题。代码评审一般是一两个人(可能甚至是团队外部的人)去审查对方要合入主干分支的代码,更适合外部人员提交代码到主干这种 GitHub PR 分支管理模式。

我所在项目的团队每天会做 Code Diff ,这是个必须的实践。团队规模在几人以内可以让每个人都有时间讲解自己的代码,如果代码太多,那可以给每个人一个时间限制。如果团队太大那可以拆分成多个 stream 来管理,总之 Diff 的人员不能太多,但每天都应该花时间做,因为收益要高于成本,可以统一代码风格,保证可读性,提高成员技术水平。

技术文档(Technical Documentation)-TechnicalDocumentatio

56af34e8-3ad6-11ed-9e49-dac502259ad0.jpg

技术文档与代码一样应该得到开发者同等的重视,但有太多文档与代码不同步的场景出现,导致文档的可用性大大降低。为什么会出现这种问题?一方面是因为开发者重视度不够的问题,另外一方面是因为写一份好的技术文档并不是一件简单的事情。

如何写一份好的技术文档?推荐阅读如下的文章:

•Technical Writing for Developers[3]•Technical Writing | Google Developers[4]•SEO Copywriting Guide[5]

开发人员不喜欢文档的另外一个原因在于,代码和文档的工作流程并不相同,一般文档都存放在与代码不同的位置,比如某个FTP目录以Word的格式存在。要是文档的编写可以和代码在同一套工作流里,就能极大的降低开发者的心智负担,这正是Docs-as-code[6]的设计理念,具体的流程实践可以看这篇文章:

•Working in public — our docs-as-code approach[7]

测试(Testing)

56daa272-3ad6-11ed-9e49-dac502259ad0.jpg

测试是软件工程过程中很重要的一个组成部分,而这里的测试主要指自动化测试过程,人工测试占比很少。测试也有一个金字塔模型,如下图所示:

57438fc6-3ad6-11ed-9e49-dac502259ad0.jpg

关于测试金字塔的细节,推荐阅读这篇文章:

•The Practical Test Pyramid[8]

开发人员写自动化测试有如下好处:

•更少的Debugging:有了自动化测试后,系统的很多行为可以通过测试代码观察到。当然Bug一旦产生说明测试代码覆盖不全面,需要补上相关的测试,久而久之,测试代码就形成了非常全面的防护网。•提升对代码变更的信心:当有了测试防护网后,对代码一旦产生破坏性的更新,测试代码会失败,这就给开发人员机会在部署前去修复此问题。•测试代码是更好的文档:当面对一个完全陌生的代码库时,除了有限的文档,另外一个了解系统行为的方式就是看测试代码。测试代码相比文档,有着更全面清晰的业务细节,能给予开发人员更多的信息去了解此业务系统。•让代码评审更简单:测试代码相比生产代码更接近业务视角,能让评审人员从业务系统对外行为的视角去了解生产代码的意图。这样也能让评审人员做出更有效的反馈意见。•好的测试反向提升代码设计:要让系统模块具备一定的测试性才能写出测试代码,所以有测试的代码从设计的角度看,其可读性与解耦度相比没有测试代码的要更高。敏捷实践中推崇的TDD(Test Driven Development)就是一种通过测试驱动出好的实现代码的实践。•自动化测试让持续交付变的更容易:如果没有自动化测试的帮助,代码部署上去后出Bug的概率要更高,这会提高系统交付的时间。

没有测试代码的系统是遗留系统。

单元测试(Unit Testing)

575acf92-3ad6-11ed-9e49-dac502259ad0.jpg

单元测试作为占比测试金字塔最大部分的底座,重要性不言而喻。它的优势很多,但Google在多年的实践中发现,提高单元测试的可维护性非常重要。而难以维护的测试代码主要有两方面造成:

•测试脆弱:当在代码重构、添加新特性及修复Bug时,会出现一些测试无法跑通,只能通过修改测试的方式来解决,这说明已有的测试很脆弱。好的测试应该只有在系统的业务行为发生改变时,才需要修改生产代码和测试代码。造成测试脆弱的原因有很多种,可能的原因包括测试隔离没做好,比如依赖了很多共享的全局性状态,或者测试了非公开的函数或方法,又或者测试的粒度过细,把很多实现细节给测试了。•测试不清晰:不清晰的原因也有很多方面,比如测试的名称并没有体现其测试意图,在单个测试中测试了一些不必要的行为,又或包含了很多无关的信息。

要提高可维护性,一些好的实践包括以下方面:

•测试行为而非方法:很多测试框架如Junit都倡导Given/When/Then三段式测试编写方式,这样可以从验收标准(Acceptance Criteria)的业务视角去编写测试,而非针对单个函数或方法去编写测试(这很容易写出脆弱的测试)。•测试名称应提现测试行为:当单元测试失败时,最先看到的就是测试失败单元的名称,好的测试名称能以最直接的方式体现该测试意图,所以测试名称长一些也可以。•测试不应包含逻辑:因为测试单元本身并没有额外的测试,如果测试包含了比较复杂的逻辑,可能会导致测试代码的Bug。所以测试代码中尽可能不包含逻辑计算的过程。•DAMP(Descriptive And Meaningful Phrases)原则:在生产代码上业界倡导DRY[9](Don't repeat yourself)的基本原则。而在测试代码中,正如上面几条实践表明,一定程度上的代码冗余是有必要的,这能帮助我们编写出简单而清晰的测试代码。

单元测试的代码执行速度一定要快,但在要测试的生产代码中,可能包含了执行速度很慢的代码,比如网络或文件等I/O操作,又或者对数据库的请求,甚至需要整个应用启动来获得完整的执行环境。如何将这类慢的代码与真正要测试业务逻辑的代码隔离开来?那就是接下来要介绍的测试替身技术。

测试替身(Test Doubles)

57c95aca-3ad6-11ed-9e49-dac502259ad0.jpg

测试替身能通过一些模拟或伪造的技术来控制被测试代码的执行路径,比如在OOP中我们可以通过接口的多个实现,来完成生产代码与测试代码的不同实现。

由于测试替身技术本身非常成熟,所以本文不做基本的介绍,推荐阅读这篇文章进一步了解:

•TestDouble[10]

在Google的多年实践中发现,测试替身很容易被滥用,造成很多脆弱的测试,而被滥用最多的就是打桩(Stubbing)技术。不同替身技术都有其适用场景,推荐的一个决策流程是:

•如果生产代码的执行时间足够快,那就不需要替身技术,直接测试生产代码;•如果伪造(Faking)的实现成本很低,且伪造的保真度够高(能尽可能模拟真实的使用场景),则推荐使用伪造替身技术;•如果在前两者都不可用的情况下,仅被测试代码只依赖少量函数或方法的返回值时,可以使用打桩(Stubbing)替身技术;•交互测试(Interaction Testing)替身技术谨慎使用,如果要用也仅在需测试函数副作用或调用次序时使用,并且不要过度测试不必要的数据;

较大型的测试(Larger Testing)

57e67d80-3ad6-11ed-9e49-dac502259ad0.jpg

在测试金字塔的顶端是占比只有20%的集成测试与E2E测试,虽然占比少,但其却可解决单元测试的以下问题:

•保真度的问题:单元测试因使用测试替身来加速执行时间,但替身与实现本身就存在保真度的问题,一旦被替身的实现发生改变,单元测试因模拟行为未变,可能造成一些意想不到的Bugs。•环境配置的问题:环境的问题只能在接近生产环境的测试环境(如UAT)环境中去测试与发现问题,这是单元测试无法覆盖的测试范围。如Google的一些重大全球性的Bug都和环境配置问题有关系。•负载下的问题:在压力测试下,系统的行为表现如何?性能是否能达到业务要求?这类非功能性的需求测试只能在E2E测试中完成。•预期外的行为与副作用:单元测试是在开发者预期的视角下完成的,所以存在一定的视角盲区。在一个接近生产环境的测试环境测试是发现这类问题最好的办法。•紧急行为和真空效应:如果系统的运行时环境发生一些意外的修改,如集群网络配置或部署配置发生变更,这类问题也只能在集成环境中发现。

较大型测试的编写与维护都是成本高昂的,在我们项目实践中,一般和业务系统强相关的集成测试和部分E2E测试都是业务开发团队完成的。但一些公共的E2E测试,比如某个全局性的功能性测试,可能由一个独立的小组完成,也可能只完成一个MVP的版本,之后由业务系统维护团队开发完成。

推荐进一步阅读的文章:

•浅谈契约测试[11]•契约测试之核心解惑[12]

弃用(Deprecation)

57fdc936-3ad6-11ed-9e49-dac502259ad0.jpg

代码是资产还是负债?Google的答案是负债,因为代码需要不断的维护才能正常工作。负债是有高昂的利息,降低负债最好的办法就是在不需要的时候砍掉它。而这就是弃用过程的价值。

对开发人员来说,弃用是个难以接受的过程,因为幸苦写的代码,很难下定决心去销毁它。所以一个中庸之道是在代码将要被弃用前,想办法通过演进的方式给予其二次生命。如果非要弃用,也只是停止维护和运行,旧的代码依旧会在代码仓库中可被搜索到,历史记录也会被保留。

我的个人项目实践是,下线一个系统是一件需要重视的过程。一个系统一旦被发布,它被使用的场景就很难以想象,API的用户可能会以意想不到的方式去使用它。所以尽可能通过代码搜索去找到其被使用的场景,之后再给充足的Deadline广而告之,甚至可以主动与用户沟通,确保不会让其出现大的损失。

总结

代码可能只会被写一次,但会被读很多次。所以软件工程中的过程部分主要致力于解决代码可读性的问题。无论是风格指南、代码评审、文档甚至自动化测试,很大程度上都在为提高代码可读性。

写代码很容易,能写出易懂的代码却有难度。所以从这个角度看,写代码是个入门简单精通却难的技能,需要我们不断的精进,通过多种实践去提高这个技能。希望这篇文章能让你对写代码这件事有更多的理解。

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Google
    +关注

    关注

    5

    文章

    1714

    浏览量

    56802
  • 代码
    +关注

    关注

    30

    文章

    4557

    浏览量

    66870

原文标题:Google软件工程之过程篇

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Cognition发布首款AI软件工程师Devin

    据报道,Cognition公司今日公布了其首款人工智能软件工程师——Devin,掀起了打造软件模式变革的序幕。该产品在SWE-bench代码测验中展现出卓越表现,甚至超过了部分顶级人类工程
    的头像 发表于 03-13 10:57 384次阅读

    如何构建linux开发环境和编译软件工程、应用程序

    前文介绍了如何使用官方提供的镜像文件启动开发板,本文将说明如何构建linux开发环境和编译软件工程、应用程序。
    的头像 发表于 01-03 12:31 487次阅读
    如何构建linux开发环境和编译<b class='flag-5'>软件工程</b>、应用程序

    嵌入式软件工程师常用的

    最近我换工作了,看见不同嵌入式软件工程师用的平台都不一样,所以我整理了一下。PlatformIO:多平台支持:PlatformIO支持多种嵌入式平台,包括Arduino、ESP8266、ESP32
    的头像 发表于 12-24 08:00 239次阅读
    嵌入式<b class='flag-5'>软件工程</b>师常用的

    嵌入式硬件和软件哪个好?

    嵌入式硬件和软件哪个好? 嵌入式软硬件工程师哪个更有前途呢?一起来看看。 嵌入式是分为软硬件工程师的,首先我们先来看看嵌入式硬件工程师吧! 嵌入式硬件开发
    发表于 12-05 15:17

    Google 向生态系统开放可靠的低延迟硬件传输系统 Falcon

    Google Cloud 首席软件工程师 在 Google,我们长期使用以太网解决规模化问题,重构传输层,从而满足突发高带宽、高速率和低延迟的工作负载需求。例如对象存储这一工作负载长期以来需要这些网络属性
    的头像 发表于 11-10 17:45 348次阅读
    <b class='flag-5'>Google</b> 向生态系统开放可靠的低延迟硬件传输系统 Falcon

    奋楫数智蓝海 &quot;信华信软件工程领域大模型&quot;正式发布

    大连2023年11月2日 /美通社/ -- 10月31日,由信华信技术股份有限公司(以下简称信华信)主办的"聚势谋远 智胜未来"人工智能领域应用高端论坛暨信华信软件工程领域大模型发布会成功举办
    的头像 发表于 11-02 15:45 366次阅读
    奋楫数智蓝海 &quot;信华信<b class='flag-5'>软件工程</b>领域大模型&quot;正式发布

    基于模型的方法在民机机载软件中的应用

    机载软件适航标准对软件研制过程、生命周期数据以及符合性证据等都提出了明确的要求。然而,这些过程要求都是建立在欧美80~90年代软件工程实践的
    的头像 发表于 10-27 15:30 262次阅读
    基于模型的方法在民机机载<b class='flag-5'>软件</b>中的应用

    软件无线电的主要原理及技术

    本文主要介绍了软件无线电的概念、主要原理、关键技术及在生活的广泛应用。它是以开放性、标准化、模块化、通用性、可扩展的硬件为平台,通过加载各种应用
    发表于 09-22 07:54

    嵌入式软件好还是硬件好?

    电路、功放电路、高速信号传输线的匹配电路等;故障定位、解决问题的能力;设计文档的组织编写技能! 那对于嵌入式软件工程师来说: 嵌入式软件工程师领域较新,他的发展也是很快的,像这类技术都是看经验的,经验
    发表于 09-18 15:31

    贴装中软件故障及排除

    制造商的软件测试流程都经历了从软件工程测试,到在特定贴片生产厂商处的新产品测试(Beta Testing) 这一过程
    发表于 09-18 15:14 220次阅读
    贴装中<b class='flag-5'>软件</b>故障及排除

    软件建模原则包括哪些内容

    软件建模正在成为一种普遍的技术来帮助软件工程师理解。
    的头像 发表于 08-29 10:07 847次阅读
    <b class='flag-5'>软件</b>建模原则包括哪些内容

    软件过程定义是什么 软件过程的要素包括哪些

    软件过程的完整定义还可能包括角色和能力、IT支持、软件工程技术和工具,以及执行过程所需的工作环境,以及用于确定执行过程的效率和有效性的方法和
    的头像 发表于 08-28 10:45 793次阅读
    <b class='flag-5'>软件</b><b class='flag-5'>过程</b>定义是什么 <b class='flag-5'>软件</b><b class='flag-5'>过程</b>的要素包括哪些

    为什么嵌入式软件工程师需要掌握 Linux?

    ,都默认支持 Linux 操作系统。 可以说, 打开 Linux 这扇门,你才是合格的软件工程师 。如果不能
    的头像 发表于 07-21 18:15 1350次阅读
    为什么嵌入式<b class='flag-5'>软件工程</b>师需要掌握 Linux?

    GB/T 11457-2006信息技术 软件工程术语

    本标准定义软件工程领域中通用的术语,适用于软件开发、使用维护、科研、教学和出版等方面。
    发表于 06-05 09:42 1次下载

    Google Drive推荐的图像尺寸是多少?

    发布图片时我看到的都是;未登录时,是一个小图标,图标旁边带有“图像”。 尝试过使用 Google Drive 托管图片;登录或未登录均无效。另外,尝试过附加文件,然后复制链接地址并在图像标签之间粘贴我也尝试过调整图像大小。 包含图像的过程是什么?推荐的图像尺寸是多少?
    发表于 05-11 08:11