Skip to content

第 42 本《程序员的 README》

简介

对于刚刚成为软件工程师的新手来说,知道如何编写代码只是成功了一半。你可能很快就会发现,学校并没有教授在现实世界中至关重要的技能和工作中必要的流程。本书恰恰填补了这一环节,它是作者十多年来在大型公司指导初级工程师工作的教程,涵盖软件工程的基础知识和最佳实践。

本书第 1~2 章讲解当你在公司开启你的职业生涯时会发生什么;第 3~11 章会扩展你的工作技能,教你如何使用现有代码库、解决和防止技术债、编写生产级软件、管理依赖关系、有效地测试、评审代码、交付软件、处理 On-Call 时的事故和构建可演进的架构等;剩余章节涵盖管理能力和职业阶梯的提升等相关内容,例如敏捷计划、与管理者 合作以及成长为资深工程师的必经之路。本书中非常重要的一部分内容是教你如何应对糟糕的管理,以及如何调整自己的节奏。

本书内容不仅浅显易懂,还覆盖整个软件开发周期,是一本技术主管希望每名新入行的工程师在开始工作之前都能阅读的书

阅读笔记

《程序员的README》 克里斯·里科米尼 德米特里·里亚博伊 281个笔记

◆ 点评

2024/2/19 认为好看 读完这本书的感觉,也是有点相见恨晚,确实读这本书要趁早,很多知识大学和工作都不会有人教你,都需要你主动去学和请教他人。所以说,它比较全面的介绍成为一名软件工程师的过程内容,可以让你少走很多弯路,比较全面的了解一个软件生命周期的过程,培养你的个人能力和工作全局观吧。特别是对新人刚入行的时候,有一个指导工作各个方面流程及实践的教程,对个人的成长和融入团队有非常大的帮助吧

印象深刻的几个章节中讲到:在进入职业生涯阶段会遇到的一些问题及如何解决,比如自己遇到问题不好意思问同事,死磕琢磨很久浪费了很多时间,还有遇到生产事故自己紧张害怕的要死,慌不择路只会适得其反等等类似的情况,作者建议我们应该“请保持开放的心态,好学深思,渴望提高,不惧破旧习,不惧提问题。”因为优秀的工程师通常会以指导和协助他人为荣,而且当你“向同事提问和学习是快速成长和习得新技能的有效方式”,所以不要吝啬你的主动哈,珍惜这段时间,争取最大努力快速提升自己咯。还有如何克服工作中常见的“冒充者综合征”和邓宁-克鲁格效应、如何阅读开源项目、如何向同事提问方式等等,都有很多讲解帮助

在提升工作技能方面:如何平衡“软件的熵”和“技术债”也有一些讲究和方法。如何代码章节方面介绍了很多注意事项和技巧,包括经常听到的“不要重复自己”(Don’t repeat yourself,DRY)是一个通常被教导的原则。如何晋级需要具备的几个能力有技术知识、执行力、沟通能力、领导力,我是非常认可,毕竟自己也是计算机专业科班出身,对技术要求及作者说到这几个能力都有刻意练习,比如写作水平差就平时多练习写技术调研方案文档、业务相关讲解文档、技术相关讲解或指南文档等等并分享团队阅读,收集改进反馈提升自己

在 On-Call 阶段印象深刻的一句话是:“你最好的能力是随时响应。”这句老话是成功 On-Call 的关键。跟我轮值时候的一些解决问题方式不谋而合,自己平时也有应用类似的方式解决,但不够成体系的、规范的执行,也是自己做的不够好的地方。对于向上管理方面,如何对自己成长负责和工作汇报有更深刻的理解,之前以为自己做好手上的工作就行,还需要站在更高的角度思考问题及思考团队贡献、自身向上成长问题。对于职业规划方面,如何成为 T 型人才,未来发展等,但有些讲解不够全面,蜻蜓点水而已,可以结合《远见:如何规划职业生涯 3 大阶段》一起学习

还有其他方面也是很不错的,比如测试方面相关知识、设计文档撰写、代码评审、软件交付等等章节都非常详细,对于我这个工作几年的人,都还有很多不懂的或者没有遵守相关编写代码规则去做,有点惭愧,哈哈哈

总体来说,还是很不错的程序员指南,新人和老手阅读都会有受益,但可能新人阅读会受益更大吧,还有就是保持持续学习💪🏻

◆ 推荐序

2024/2/6 发表想法 工匠精神,好的东西都是精雕细琢过来的,代码也是如此。大佬也是从菜鸡一步一个脚印走过来的,得学会从自身找原因学习,提高自我要求,才能一步步写出好代码

一名成熟的软件开发者的标志是打破固有的习惯,批判性地回顾旧代码,发现瑕疵,做到自省,且为没多做些什么而感到羞愧。

一名成熟的软件开发者的标志是打破固有的习惯,批判性地回顾旧代码,发现瑕疵,做到自省,且为没多做些什么而感到羞愧。

2024/2/6 发表想法 职场新人总是羞愧于向他人提问,怕会展示自己的能力不足或简单无知,但对于前辈或同事来说,也是乐于将自己过来经验分享给别人,少走些弯路。但也要注重自己提问的方式和请教的态度

向同事提问和学习是快速成长和习得新技能的有效方式

向同事提问和学习是快速成长和习得新技能的有效方式

资深工程师往往在聚精会神工作时会因为被打扰而失去在脑海中已构建的系统的短期记忆,但大多数资深工程师都很愿意提供帮助,优秀的资深工程师更是以指导和协助他人为荣。如果你在寻求帮助时感受到了敌意,大可不必心烦意乱,因为这在每个人身上都可能发生。不要让某一次糟糕的遭遇阻断了你再次寻求帮助的欲望。

请保持开放的心态,好学深思,渴望提高,不惧破旧习,不惧提问题。

◆ 译者序

变动的需求、阻滞的沟通、糟糕的管理和紧迫的工期,总有些时刻会令人产生倦怠

在实际的工作中,成功地交付软件并不是只有唯一的路径可走。如何衡量与之匹配的需求、成本和风险才是考验团队的地方。

2024/2/6 发表想法 当你学的越多、懂得越多,就会越觉得自己对于世界充满好奇和学习动力,好像万物新生,随时可以重头开始一样

翻译完本书的最后一章时,正好是我踏入软件行业的12年整,此时的我却觉得自己的职业生涯好像才刚刚开始。

翻译完本书的最后一章时,正好是我踏入软件行业的12年整,此时的我却觉得自己的职业生涯好像才刚刚开始。

◆ 前言

然而要成为一名高效的软件工程师,你还需要那些学校里没有教授过的技能。而本书将会教你这些技能。

诸如如何获得帮助、如何撰写设计文档、如何维护旧代码、如何On-Call(待命)、如何规划你的工作以及如何与你的管理者和团队互动

◆ 第1章 前面的旅程

一名成功的软件工程师究竟是什么样子的呢?以及如何成为一名成功的软件工程师呢?

每个人都是从入门级工程师开始做起的。如果想晋级,你就需要具备下面几个核心领域中所需要的能力。 ● 技术知识:你知道计算机科学的基础知识。你知道如何使用集成开发环境(IDE)、构建系统、调试代码和测试框架。你熟悉持续集成、系统指标和监控、配置和打包系统。你积极主动地创建和改进测试代码。在做架构决策时,你会考虑到长期运维。 ● 执行力:你通过用代码解决问题来创造价值,并且你了解你的工作和业务之间的联系。你已经可以构建并部署中小型的特性。你会编写、测试和评审代码。你分担On-Call的职责,调试运维问题。你是积极主动并且可靠的。你参加技术讲座、阅读小组、面谈和路演。 ● 沟通能力:你能同时以书面和口头的形式进行清晰的沟通。你能够有效地给予和接受反馈。在模棱两可的情况下,你会主动寻求帮助并得到明确的结果。你能以建设性的方式提出问题和定义课题。你在可能的情况下可以提供帮助,并开始影响同事。你会文档化你的工作。你撰写清晰的设计文档并征求反馈意见。在与他人打交道时,你富有耐心和同理心。 ● 领导力:你能在指定的工作范围内独立地完成工作。你能迅速地从错误中学习。你能很好地处理变动和模糊的问题。你积极参与到项目和季度的规划中。你能帮助新的成员融入团队。你可以向你的管理者提供有意义的反馈。

这是坎宁安定律的一个应用,该定律认为:“在互联网上获得正确答案的最好方法并不是提出问题,而是发布错误的答案。”

过度集中在细枝末节上的讨论总是会很冗长,这种现象被称为“自行车棚”(bike-shedding)效应

多提问,并经常让团队评审你的工作成果。

◆ 第2章 步入自觉阶段

能力的4个阶段:“无意识的无能力”(unconscious incompetence)、“有意识的无能力”(conscious incompetence),“有意识的有能力”(conscious competence)和“无意识的有能力”(unconscious competence)。具体说来,无意识的无能力意味着你无法胜任某项任务,并且没有意识到这种差距。有意识的无能力意味着你虽然无法胜任某项任务,但其实已经意识到了其中的差距。有意识的有能力意味着你有能力通过努力完成某项任务。最后,无意识的有能力意味着你可以很轻松地胜任某项任务

2024/2/14 发表想法 技术领域更新迭代太快了,新旧技术层出不穷,新的事物发展也在不断变化。有些技术方案当初做的时候适合,但现在有更好的方案或有更适合的方案,考虑团队长远发展和业务发展都需要学习跟进的,没有一成不变的东西,与时俱进吧

无论你是一名刚毕业的学生还是一名经验丰富的老手,如果你不学习,你就会落后。

无论你是一名刚毕业的学生还是一名经验丰富的老手,如果你不学习,你就会落后。

2024/2/14 发表想法 生活和工作平衡也很重要

切记善用个人的时间——虽然说持续进步非常重要,但是把所有清醒的时间都花在工作上是不健康的。

切记善用个人的时间——虽然说持续进步非常重要,但是把所有清醒的时间都花在工作上是不健康的。

2024/2/14 发表想法 对于新手来说,一些事故在所难免,但要尽量避免这类事情的发生,谨慎一点。对于自己不太确定但有影响的事最好多问同事确认下,对于新人,大部分同事都会很友好的,但因为自己的个人原因造成的过错,就有点不应该,发生了也不要恐慌,第一时间先解决问题,后续再复盘自己的问题,避免类似情况发生

错误难免会发生。每名工程师都有类似的故事。尽你所能,努力理解你在做什么,但要知道这种事情总会发生

错误难免会发生。每名工程师都有类似的故事。尽你所能,努力理解你在做什么,但要知道这种事情总会发生

降低系统风险并使这些错误不那么致命是你的管理者和团队的工作。如果你失败了,也不要被击垮:写下经验教训,然后继续前行。

请每周都花一部分时间去阅读。可供阅读的内容有很多:团队文档、设计文档、代码、积压的任务票、书籍、论文和技术网站。不要试图一下子把所有东西都读完。

2024/2/15 发表想法 阅读优秀的代码也是提升自己最快的方式之一

不要只读你自己的代码库,还要去阅读高质量的开源项目,特别是那些你使用的类库。不要像阅读小说一样从前到后地通读代码:请利用你的IDE来浏览代码。为关键的操作绘制控制流和状态图。仔细研究代码的数据结构和算法。注意那些临界值的处理。留意那些惯用写法和风格,也就是去学习“本地方言”(local dialect)。

不要只读你自己的代码库,还要去阅读高质量的开源项目,特别是那些你使用的类库。不要像阅读小说一样从前到后地通读代码:请利用你的IDE来浏览代码。为关键的操作绘制控制流和状态图。仔细研究代码的数据结构和算法。注意那些临界值的处理。留意那些惯用写法和风格,也就是去学习“本地方言”(local dialect)。

这种经历让德米特里学会了慢慢来,为了理解而阅读,而且永远都不会相信变量名称。

你通常可以用1.5倍速甚至2倍速观看视频,以节省时间,但不要被动地观看。你需要做笔记来帮助记忆,并学习任何不熟悉的概念或术语。

2024/2/15 发表想法 确实可以少走很多弯路,我刚入行的时候我也希望可以遇到这样的前辈教导、指引我前行,后来没有找到。但现在我也在成为当初那个苦苦追寻的人了,带过新人之后,才懂得如何教学相长,输出是最好的输入吧

跟随一名高级工程师是学习新技能的好方法。

跟随一名高级工程师是学习新技能的好方法。

结对编程(pair programming)也是一种很好的学习方式。两名工程师一起写代码,轮流打字

不要根据你认为你需要学习的领域来选择项目。找到你有兴趣去解决的问题,并使用你想学习的工具来解决这些问题。一个可以从内激励你的目标会让你更长时间地参与,你也会学到更多。

新手工程师会担心打扰队友而试图自己解决所有问题,这样做既慢又没有效果

使用这3个步骤:做研究,提出明确的问题,并恰当地安排解决你的问题所需的时间。

尝试自己寻找答案。即使你的同事知道答案,你也要付出努力,这样你会学到更多。如果你没有找到答案,当你寻求帮助时,你的调查仍然会成为你的起点

如果你找不到任何线索,试着自己通过实验来解决它。记录下你在哪里寻找过,你做了什么,为什么这么做,发生了什么,以及你学到了什么。

2024/2/16 发表想法 这是很好的请教提问方式,至少让人感觉提问前你是做了很多努力的,你不是一个遇到问题就靠别人的人。很多新人会直接问问题,没有做任何实际的独立思考和动手解决问题的尝试,一两次别人可以这样帮你,但是次数多了容易让人反感或厌烦,别人没有义务教你、帮你解决问题,每个人都有自己的工作要做呢。主要是你这样做了,别人可以根据你提供有效的问题信息快速定位问题提供解决方案,而不是从头开始排查问题原因,节约彼此时间

在提出问题时描述你已经知道的情况。不要只是分享你的原始笔记。简要地描述你所做的尝试和发现,这表明你已经花了很多时间去试图自己解决这个问题。这样做也会给别人一个回答你的起点。

在提出问题时描述你已经知道的情况。不要只是分享你的原始笔记。简要地描述你所做的尝试和发现,这表明你已经花了很多时间去试图自己解决这个问题。这样做也会给别人一个回答你的起点。

如果你需要的人很忙,同时你又不想自己的工作进程被卡住,这时候你就需要找到一种异步的沟通方式。

在网络通信中,组播(multicast)是指将消息发送到一个组而不是个人目标;异步(asynchronous)是指可以稍后处理的消息,而不需要立即响应。这些概念也适用于人们之间的通信。

在你设置的会议议程中应包括这个清单,不要只靠脑袋来记问题,也不要事前不做功课就来参加。

一般有两个常见的障碍会影响许多工程师,即“冒充者综合征”和邓宁-克鲁格效应。

尽管有着杰出的学术和职业成就,经历着冒充者现象的女性仍然坚持认为她们真的不聪明,而且还愚弄了任何不这么想的人。众多的成就似乎并不影响冒充者的信念,而这些成就本身就是能充分证明智力水平卓越的客观证据。

冒充者综合征会自我强化。每一个错误都会被看作能力匮乏的证明,而每一项成功都是优秀“冒充者”冒充的证据。一旦某个人进入了这个循环,就很难摆脱它。

当你取得一些成就的时候,那是因为你真真切切地做到了,你并不只是运气好。

2024/2/16 发表想法 有时候自己突破技术难关或者解决难题方案时候,一开始觉得好难做,以自己的能力根本不可能完成,最后还是硬着头皮死磕解决、做出来了,那一刻的喜悦、成就感无与伦比。但后来又会想这只不过是简单的问题而已,解决了没什么大不了的,反而觉得自己要学习的东西更多😓是这样子的,当我们做超出自己能力的事情的时候,多少是有点恐惧的,甚至是有点不想去完成。但我们下定决心去做的时候,不管过程多么困难,只要最终能够完成。一开始会很开心,后面又会觉得理所应当,甚至自己的能力还需要多学习提高,其实是缺少自我肯定去建立信心和缺少他人的鼓励、认可。所以当你觉得自己做一件很困难的事情,最终做成了你可以把这件事情的过程及结果记录下来,适当的去分享给你信任的人,从他人中获得改善建议及鼓励认可的能量

请你尊敬的人来告诉你,你做得怎么样。这个人可以是你的管理者、导师,或者只是你仰慕的工程师。重要的是你要信任他们,并觉得与他们谈论自我怀疑是安全的。

请你尊敬的人来告诉你,你做得怎么样。这个人可以是你的管理者、导师,或者只是你仰慕的工程师。重要的是你要信任他们,并觉得与他们谈论自我怀疑是安全的。

与冒充者综合征相反的是邓宁-克鲁格效应。这是一种认知偏见,人们认为自己比实际情况更有能力

无意识的无能力”阶段的工程师不知道自己不知道什么,所以他们不能准确地评估自己和他人的表现。他们太自信了。他们总是到处批判公司的技术栈,抱怨代码的质量,贬低设计。他们确信自己的想法是正确的。他们的默认模式是直接回绝或无视反馈。拒绝所有的建议会亮起一盏巨大的红灯:完全自信标志着盲点

幸运的是,邓宁-克鲁格效应在新手工程师中并不常见。有许多方法可以对抗它:有意识地培养好奇心;对犯错持开放态度;找到一位受人尊敬的工程师,询问他你做得怎么样,并真正地倾听;讨论设计决策,尤其是那些你不同意的决策,问问为什么会做出这样的决策;培养一种权衡利弊的心态,而不是非黑即白的心态

行为准则 

◆ 第3章 玩转代码

混乱的根源,即“软件的熵”和“技术债”

2024/2/16 发表想法 随着对应负责人员调整和业务的发展,对于不熟悉的代码和为了快速业务上线,很多人的做法都是“能跑就行”,不需要花费太多时间去了解原来的业务代码逻辑和适当代码优化、重构维护,当然也很大程度上取决于对应开发负责人的自我要求和专业能力

混乱的代码是变化的自然副作用,不要把代码的不整洁归咎于开发者。这种走向无序的趋势被称为软件的熵(software entropy)。

混乱的代码是变化的自然副作用,不要把代码的不整洁归咎于开发者。这种走向无序的趋势被称为软件的熵(software entropy)。

幸运的是,软件的熵可以被管理

技术债(technical debt)是造成软件的熵的一个主要原因。技术债是为了修复现有的代码不足而欠下的未来工作

要成为技术债,这个问题必须迫使团队“支付利息”,或者代码必须冒着触发严重问题的风险,因为严重问题需要紧急支付。

 谨慎的、有意的技术债(右上)是技术债的典型形式:在代码的已知不足和交付速度之间进行务实的取舍。只要团队有规划地解决这个问题,这就是好的债务。

从这个矩阵中得到的一个重要启示是,技术债总是不可避免的,因为你无法防止无意中的错误。技术债甚至可能是成功的标志:项目只有存活了足够长的时间,才会变得无序

要边做边解决,着手去做小幅的重构。在小幅的、独立的提交(commit)和拉动请求(pull request)中推动问题的修改。

下面是讨论技术债的一个优秀的模板: 1.按事实陈述情况; 2.描述技术债的风险和成本; 3.提出解决方案; 4.讨论备选方案(不采取行动也是备选方案); 5.权衡利弊。

以书面形式提出你的建议。不要把你的呼吁建立在价值判断上(“这代码又老又难看”),将重点放在技术债的成本和修复它带来的好处上。要具体,如果有人要求你证明这种改动会带来哪些好处,不要感到惊讶。

所谓重构,是指在不改变软件行为的情况下改进内部代码结构。它经常发生在添加新特性的时候,因为它使新特性可以更容易地被添加。而在修复bug的过程中,则经常删除代码。

改变现有的大型代码库是一项需要经过多年甚至几十年锤炼的专业技能

对如何安全地在现有代码库中修改代码提出了以下步骤: 1.定义变更点; 2.寻找测试点; 3.打破依赖关系; 4.编写测试; 5.进行修改和重构。

使用重构以打破依赖关系是工作中风险最大的部分。它甚至可能涉及改变预先设定好的测试用例,这使得它更难以检测到原有的行为是否改变。采取小步前进的方式,在这个阶段不要引入任何新特性。确保你能快速地运行测试用例,这样你就能频繁地测试。

有各种各样的技术手段可以打破依赖关系,包括以下几种: ● 将一个大的、复杂的方法拆分成多个小的方法,这样就可以分别去测试独立的特性片段; ● 引入一个接口(或其他中介),为测试提供一个复杂对象的简单实现——不完整,但要满足测试需要; ● 注入明确的控制点,允许你模拟难以控制的执行的切片,如时间的推移。

互联网上的编程传说经常引用童子军的原则:“住过的营地要比住之前更干净”。

在不影响整个项目持续运转的情况下要持续地重构工程,这样重构的成本就会平摊在多次的版本更迭中。

尽量将清理代码的提交和改变行为的提交各自分开。

代码异味(code smell)是一个术语,专指那些不一定是bug,但采用了已知会导致问题的代码模式,通常“闻起来很怪”

保持你每次重构代码的体量很小。为代码变更算法中的每个步骤提交单独的拉动请求

2024/2/16 发表想法 不要为了重构而重构,可以参考投入产出比来衡量结果值不值得去做

重构的成本也可能超过其价值。正在被替换的旧的、废弃的代码不需要被重构,同理,低风险或很少被触及的代码也不需要。在重构的时候要务实。

重构的成本也可能超过其价值。正在被替换的旧的、废弃的代码不需要被重构,同理,低风险或很少被触及的代码也不需要。在重构的时候要务实。

重置你的分支,压缩你的提交,并在提交代码修改供评审之前写一份清晰的提交信息。

。想用干净的代码和现代技术栈来工作是很自然的想法,但重构代码或忽视标准的诱惑是危险的。重构代码如果做得不好,会破坏代码库的稳定性,而且重构会以牺牲发布新特性为代价

任何技术创业公司必须做的主要的事情是建立一个产品,这个产品在做某件事情时至少要比目前流行的方式好十倍。两倍或三倍的改进不足以让人们快速或大量地转向新事物。

2024/2/16 发表想法 有时候适合公司业务发展的技术栈就是最好的,不管新旧技术栈,不要为了与时俱进盲目更新,毕竟是已经经过时间的证明了

软件是一个快速发展的领域。新的工具、语言和框架不断地出现。与网上“大火”的东西相比,现有的代码看起来有些过时。然而,成功的公司留用旧的代码——比如旧的类库和旧的模式——是有原因的:成功需要时间,而在技术上大动干戈会让人分心

软件是一个快速发展的领域。新的工具、语言和框架不断地出现。与网上“大火”的东西相比,现有的代码看起来有些过时。然而,成功的公司留用旧的代码——比如旧的类库和旧的模式——是有原因的:成功需要时间,而在技术上大动干戈会让人分心

所有的技术都会发生故障,但旧的东西以可预测的方式发生故障,新东西往往会以令人惊讶的方式发生故障。缺乏成熟度意味着更小的社区、更低的稳定性、更少的文档,以及更差的兼容性。新技术甚至在Stack Overflow上有更少的答案。

为了平衡成本和收益,应该把代币花在服务于公司高价值领域(即核心竞争力)的技术上,以解决广泛的难题,并能被多个团队复用。

有些重构值得去做,但许多重构不值得。对你的重构欲望要诚实,那些代码使用了你不喜欢的语言或框架并不是一个好理由,只有在收益大于成本的情况下才应该进行重构。重构是有风险的,成本也很高。工程师们总是会低估重构花费的时间,尤其是迁移花费的时间往往很可怕。数据需要被转移,上游和下游的系统都需要同步更新,这可能需要几年甚至几十年

不要以为重构工作会很轻松,这将是一个艰难的过程。

行为准则 

◆ 第4章 编写可维护的代码

编写拥有良好防御性的代码是一种对那些运行你的代码的人(包括你自己!)富有同情心的表现

使用不可变的变量可以使并发编程变得更简单,而且当编译器或运行环境知道变量不会改变时就可以运转得更有效率。

永远不要相信你的代码接收的输入,开发人员、有问题的硬件和人为的错误都会破坏输入的数据。通过校验输入的正确性去保护你的代码,可以使用先决条件、校验和(checksum)以及校验数据合法性,套用安全领域中的最佳实践以及使用工具等方法来发现常见的错误。尽可能地提早拒绝不良输入。

也不要忽视安全问题,外部输入是危险的。恶意用户可能试图在输入中注入代码或SQL,或撑爆缓冲区以获得对你的应用程序的控制权限。使用成熟的类库和框架来防止跨站脚本攻击,总是强制转义输入的字符来防止SQL注入攻击。

熟悉开放式Web应用程序安全项目(open Web application security project,OWASP)的十大安全报告以快速建立你的安全知识体系。

精确的异常使代码更容易使用。尽可能地使用内置的异常,避免创建通用的异常。使用异常处理来应对故障,而不是控制应用程序的运行逻辑。

当你创建自己的异常时,不要把它们弄得太通用。通用的异常很难处理,因为开发人员并不知道他们正面临什么样的具体问题。

不要在应用程序的运行逻辑中使用异常。你应该希望你的代码是不出人意料的,而不是聪明的。使用异常来跳出方法常常令人困惑,并且使代码难以调试。

遵循“早抛晚捕”的原则来处理异常。“早抛”意味着在尽可能接近错误的地方引发异常,这样开发人员就能迅速地定位相关的代码。

当调用可能抛出异常的代码时,要么完全地处理它们,要么将它们在堆栈中进行传播。

有3种常见的系统指标类型:计数器、仪表盘和直方图。

系统性能通常以阈值百分比的形式来衡量,例如,从0%到99%,被称为P99。

监测以下所有的数据结构、操作和行为: ● 资源池; ● 缓存; ● 数据结构; ● CPU密集型操作; ● I/O密集型操作; ● 数据大小; ● 异常和错误; ● 远程请求和响应。

配置可以用许多方式来表达: ● 普通的、对人友好的格式的文件,如INI、JSON或YAML; ● 环境变量; ● 命令行参数; ● 定制的领域特定语言(DSL); ● 应用程序所使用的语言。

配置即代码(configuration as code,CAC)的哲学认为,配置应该受到与代码同样严格的要求。配置错误可能是灾难性的,一个错误的整数或缺失的参数就可以毁掉一个应用程序。

行为准则 

◆ 第5章 依赖管理

在现有的代码上增加一个依赖似乎是一个简单的决定。“不要重复自己”(Don’t repeat yourself,DRY)是一个通常被教导的原则。

相依性是指你的代码所依赖的代码。在编译、测试或运行期间,所有需要依赖关系的时间周期被称为依赖范围。

依赖关系是在软件包管理或构建文件中声明的:Java的Gradle或Maven配置,Python的setup.py或requirements.txt,以及JavaScript的NPM所使用的package.json。

一个好的版本管理方案,其版本都具有以下特点。 ● 唯一性(unique):版本不应该被重复使用。构件会被分发、缓存,并被自动化工作流拉取。永远不要在现有版本下重新发布更改的代码。 ● 可比性(comparable):版本应该帮助人们和工具对版本的优先顺序进行推断。当一个构建依赖于同一构件的多个版本时,可以使用优先顺序来解决冲突。 ● 信息性(informative):版本信息区分了预先发布的代码和已发布的代码,将构建流水号与构件相关联,并设置了稳定性和兼容性的合理预期。

主版本号为0被认为是“预发布”,是为了快速迭代,不做任何兼容性保证。开发者可以用破坏旧代码的方式修改API,如新添加一个必要参数或删除一个公共方法。但是主版本号从1开始后,一个项目应该保证以下内容。

● 补丁版本号是递增的,用于修复bug,并且可以向下兼容。 ● 对于向下兼容的特性,次版本号是递增的。 ● 对于无法向下兼容的变化,主版本号会被递增。

SemVer还通过在补丁版本号后添加一个“-”来定义预发布版本。小数点分隔的字母和数字的序列被用作预发布版本的标识符(2.13.7-alpha.2)。预发布版本可以在不影响主版本的情况下进行突破性的修改。

许多项目使用候选发布版(release candidate,RC)构建。早期采用者可以在正式版本发布之前发现RC中的错误。RC预发布版本有递增的标识符,如3.0.0-rc.1。然后,最终的RC被提升为正式发布版,重新发布的版本没有RC的后缀。所有的预发布版本都会被最终版本(在我们的例子中是3.0.0)所取代

SemVer的方案还允许使用通配符来标记版本范围(2.13.*)。由于SemVer承诺跨小版本和补丁版本的兼容性,

比较常见的相依性地狱的罪魁祸首是循环依赖、钻石依赖和版本冲突。

一个项目不能同时使用同一个类库的两个不同的版本,所以构建系统必须从中选择其一。

在现实中,兼容性是一个“美丽的愿望”。项目经常在没有检查兼容性的情况下就发放版本,即使是自动化也不能完全保证其兼容性。那些无法向下兼容的变化会被不经意地发版成次版本或补丁版本,给你的代码库带来巨大的破坏

添加一个依赖项的价值是否超过了它的成本? ● 你真的需要这些特性吗? ● 依赖关系的维护情况如何? ● 如果出了问题,你修复这个依赖有多容易? ● 依赖项的成熟度如何? ● 引用依赖后向下兼容的变化频率如何? ● 你自己、你的团队和你的组织对该依赖的理解程度如何? ● 自己写代码有多容易? ● 代码采用什么样的许可协议? ● 在依赖中,你使用的代码与你不使用的代码的比例是多少?

要务实,不要害怕复制代码,如果它能帮助你避免一个庞大的或不稳定的依赖关系(并且软件许可协议容许这么做)。 直接复制代码在简短的、稳定的代码片段上效果最好

将你使用的所有类库显式声明为依赖项。不要使用来自横向依赖的方法和类,即使它看起来很有效。

任何未指定版本的依赖项不仅会拉取对bug的最新修复,还会拉取更多的东西,比如它们会拉取最新的bug、软件行为,甚至是不兼容的变化。

精确的依赖范围将有助于避免冲突并减小运行时的二进制包或者文件的大小。

行为准则 

◆ 第6章 测试

糟糕的测试会增加开发人员的开销而不提供价值,并且还会增加测试套件的不稳定性。

测试也可以暴露出混乱的实现过程,“意面式”的代码,或有太多依赖项的代码,都很难进行测试。编写测试也可以迫使开发人员分别通过改进关注点分离和降低紧耦合的方式来确保他们的代码拥有良好的构造。

TDD是指在写代码之前先编写测试的实践,如果测试写好之后运行测试失败了,那么就去编写代码使其通过。TDD迫使开发人员在写出一堆代码之前思考软件的行为、接口设计和集成。

测试其实是另一种形式的文档,它说明了代码是如何被交互的。它是一名有经验的程序员开始阅读并了解一个新的代码库的首选入口

单元测试、集成测试、系统测试、性能测试和验收测试

单元测试是验证代码的“单元”,这通常指某个单一的方法或行为

集成测试验证多个组件集成在一起之后是否还能正常工作。如果你发现自己在测试中实例化了多个相互作用的对象,那么你正在写的可能就是集成测试。

系统测试是验证整个系统的整体运行情况。端到端(end-to- end,e2e)的工作流程是为了模拟在预生产环境中系统与真实用户的互动。

性能测试(如负载测试和压力测试)监控不同配置下的系统性能。

验收测试是指由客户或其代理人进行的,以验证交付的软件是否符合验收标准的测试。

模拟库用模仿真实系统提供的接口来代替外部依赖性。

测试框架可以帮助你编写和执行测试。你会发现一些框架可以帮助你统筹执行单元测试、集成测试、性能测试,甚至是UI测试。下面是框架的作用。 ● 管理测试的setup和teardown。 ● 管理测试执行和编排。 ● 生成测试结果报告。 ● 提供工具,如扩展的断言方法。 ● 与代码覆盖率工具集成

测试框架可以通过编排测试流程来帮助控制测试的速度和隔离度。测试可以串行或并行地执行。串行测试是一个接一个地执行,一次执行一个测试会更安全,因为测试之间相互影响的机会比较少;并行执行更快捷,但由于共享的状态、资源或其他污染,因而更容易出错

强制执行代码质量规则的工具被称为linter,linter可以运行静态分析并执行代码风格检查。

质量保证(QA)团队,尽管其职责各不相同,但都包括以下内容。 ● 编写黑盒或白盒测试。 ● 编写性能测试。 ● 进行集成测试、用户验收测试或系统测试。 ● 提供和维护测试工具。 ● 维护测试环境和基础设施。 ● 定义正式的测试认证和发布流程

 图6-1 风险矩阵 测试可以将代码风险向左下方转移,因为测试越多,失败发生的可能性就越低。首先应该关注代码中的高风险的区域;而那些低风险或被废弃的代码,诚如其概念所言,并不值得测试。

确定性的代码对于相同的输入总是给予相同的输出。相比之下,非确定性的代码对于相同的输入可以返回不同的结果。

测试不应该依赖于特定的执行顺序。顺序依赖通常发生在某项测试会先行写入数据,而随后的测试会假设数据已经写入的场景。这种模式很糟糕,原因有很多。 ● 如果第一个测试失败了,第二个也会失败。 ● 这使得并行测试更加困难,因为在第一个测试完成之前,你不能执行第二个测试。 ● 对第一个测试的修改可能会意外地破坏第二个测试。 ● 对测试运行器的修改可能会导致你的测试以不同的顺序运行

行为准则 

◆ 第7章 代码评审

大多数团队会在合并代码的修改之前进行代码评审。高质量的代码评审文化有助于所有具有不同经验水平的工程师的成长,并促进他们对代码库的共同理解。糟糕的代码评审文化会抑制创新,减慢开发速度,并且导致滋生怨恨情绪。

优秀的代码评审可以作为一个教学工具,传播认识,记录实现的决策,并提供代码的更改记录以确保安全性与合规性。

评审整个代码库的变更可以确保不止一个人熟悉生产环境中代码的每一行,对代码库的共同理解有助于团队更有凝聚力地扩展代码。

评审不是一个证明你有多聪明的机会,也不是一个橡皮图章式的官僚主义障碍。

代码修改由准备、提交、评审、最后批准和合并这几个环节组成。

不要执着于那些你提交评审的代码,要期待它在评审过程中发生变化,有时甚至是重大的变化

代码清单7-1 评审者: agupta, csmith, jshu, UI/UX团队。
标题: [UI-1343] 修复了在目录Header上缺失链接的问题。
描述:
 
# 概述
主页目录Header上缺失“关于我们”的链接。
现状是单击目录按钮没有反应,通过追加一个正确的链接来修正这个
问题。
 
追加了一项Selenium测试来验证本次修改。
 
# 检查列表
本次拉取请求:
 
- [x] 添加新的测试代码;
- [ ] 修改面向公众的API;
- [ ] 把设计文档涵盖在内。 这个评审请求的样例遵循了几项最佳实践

你可以通过提交评审草案来检查你正在做的事情:一项非正式的评审请求,旨在从队友那里获得快速和低成本的反馈,这可大大降低你在错误道路上走得太远的风险。

一些开发者通过提交代码评审的方式来触发持续集成(continuous integration,CI)系统来绕过这个问题,这是一种糟糕的做法。 通过提交代码评审来触发执行测试的方式是一种浪费。

2024/2/17 发表想法 就事论事而已,不要上升到吵架或者人身攻击。有人能够指出你的不足,教你怎么改正,最好可以虚心接受,当然自己有疑问或者不接受建议可以多讨论一下的,择其善者而从之

从你的代码上得到的那些批评性的评论可能让你很难接受。切记应该保持一些情感上的距离——这些评审意见是针对代码的,而不是针对你个人的,而且这甚至都不算是你的代码,将来整个团队会拥有这些代码。

从你的代码上得到的那些批评性的评论可能让你很难接受。切记应该保持一些情感上的距离——这些评审意见是针对代码的,而不是针对你个人的,而且这甚至都不算是你的代码,将来整个团队会拥有这些代码。

2024/2/17 发表想法 意见分歧很正常,人都会有认知局限的,我们觉得好的实现方式在别人眼里是不好的,或者两种方式都差不多,差异不明显都有可能。如果都说服不了对方,那就应该让团队来决定,避免个人之间的冲突,友好对待,切勿情绪上头

首先审视你自己的反应,你本能地保护你的代码只是因为你编写了它们,还是因为你的方式事实上更好?清楚地解释你的观点,如果你们还是不能达成一致,咨询一下你的管理者下一步该怎么做。团队处理代码评审冲突的方式各不相同,有的服从提交者,有的服从技术负责人,还有的服从小组的法定人数。应该遵循团队惯例。

首先审视你自己的反应,你本能地保护你的代码只是因为你编写了它们,还是因为你的方式事实上更好?清楚地解释你的观点,如果你们还是不能达成一致,咨询一下你的管理者下一步该怎么做。团队处理代码评审冲突的方式各不相同,有的服从提交者,有的服从技术负责人,还有的服从小组的法定人数。应该遵循团队惯例。

要专注于那些你可以从中学习的修改和你熟悉的代码。

在你的日历上划出代码评审时间。预定的评审时间会使你很容易继续你的其他任务,因为你知道你以后会有集中的时间段进行代码评审。这也会使你的评审保持高质量——当你有专门的时间时,你就不会对需要切换回其他任务而感到有那么大的压力。

了解修改的动机将解释具体实现的决策,你可能会发现某些修改甚至是不需要的。比较修改前后的代码也会帮助你检查正确性,并启发其他的实现想法

你需要对代码修改的正确性、可实施性、可维护性、可读性和安全性提供反馈,指出那些违反代码风格手册、难以阅读或令人困惑的代码,阅读测试用例并寻找bug以验证代码的正确性。

在评审代码时,会很自然地把注意力集中在发现问题上,但代码评审不一定全都是负面的评论。对好的东西也要进行赞扬。如果你从阅读代码中学到了一些新的东西,请明确地传达给作者。

即使是一项令你讨厌的修改,你也可以对它说些好话——如果没有别的原因,就承认它的意图和努力。

如果同样的代码风格类的问题反复出现,不要一直喋喋不休。指出第一个例子,并指出这是需要全面展开的问题。没有人喜欢被反复告知同样的事情,而且也没有必要这样做

代码评审通常在一个专门的UI中处理,比如GitHub中的拉取请求界面。不要忘记,代码评审本身也只是代码而已。你仍然可以迁出或下载那些拟议的修改,并在本地处理它们。

不要坚持要求完美,不要扩大修改的范围,要清楚地描述哪些评审意见是关键的,不要让分歧发酵。

一般来说,评审者应该倾向于批准CL,只要它处于肯定能改善正在运行的系统的整体代码运行的状况,即使CL并不完美。

尊重正在进行的修改的范围。在你阅读的过程中,你会发现改进相邻代码的方法,并产生一些关于新特性的想法,不要坚持将这些修改作为现有评审的一部分来进行。另开一张任务票来改进代码,把工作留到以后。确定严格的范围将提高速度并保持增量更改。

如果对代码修改有重大分歧,而你和作者又不能解决分歧的话,请主动提出把这个问题移交给其他专家,他们可以帮助解决相关分歧。

行为准则 

谷歌公司的《开发者代码评审指南》

◆ 第8章 软件交付

你的团队可能把整个流程——从打包到展开,统称为发布(release)。他们可能把打包一个构件称为发布,而把构件交付下载的过程称为发行(publishing)。直到一个特性在生产环境中被打开时才能称其为被“发布”了,而在这之前的一切行动都是部署(deploy)

 图8-1 软件交付流程

Gitflow使用开发分支、热修复分支和发布分支。

 图8-3 Gitflow基于特性分支的开发模式

构建软件包需要很多步骤:解决和连接依赖项、运行linter、编译、测试,最后是打包软件

高度发展的自动化催生了持续交付。通过持续交付,人力被完全从部署环节中移除。打包、测试、发布、部署,甚至展开环节都是自动化的。

在展开环节有许多策略:特性开关、熔断器、“摸黑启动”、“金丝雀部署”和“蓝绿部署”。

特性开关有时被用于A/B测试,这是一种测试用户对新特性反应的技术。如果以具有统计意义的方式对用户进行分组,用特性开关进行A/B测试是可行的。

熔断器有几个特点:它是二进制的(开/关)、永久性的,而且是自动化的。

金丝雀部署和蓝绿部署是两种非常常见的并行部署策略。

金丝雀部署用于处理高流量并会部署到大量实例的服务。一个新的应用程序版本被首先部署到一组受限的计算机上,全部用户中的一个小的子集会被路由到这个金丝雀版本

蓝绿部署指的是运行两个不同版本的应用程序:一个是主动的,一个是被动的

 图8-6 在金丝雀部署中,负载均衡器将一部分入站流量路由到新的部署中  图8-7 在一个蓝绿部署中,服务1.0被保留下来,
作为服务1.1发生故障时的备用

在灾难场景中,所有的用户都需要从一个有问题的系统中迁移出来,有能力快速启动并运行一个并行的环境善莫大焉。

摸黑启动(有时被称为影子流量)将新的代码暴露在真实的流量中,而不使其对终端用户可见,即使代码是坏的,也没有用户受到影响。

摸黑启动的软件其实仍然启用了,代码也被调用了,只是结果被丢掉了。摸黑启动可帮助开发者和运维人员在生产环境中了解他们的软件,对用户的影响最小。

 图8-8 暗中读取和暗中写入

行为准则 

艾玛·简·霍格宾·韦斯特比的《Git团队协作:掌握Git精髓,解决版本控制、工作流问题,实现高效开发》

亚马逊的构建者库也是一个伟大的免费资源,可用于交付最佳实践。该库位于亚马逊构建者的主页,那上面有关于持续交付、自动部署和回滚的帖子。

◆ 第9章 On-Call

新加入团队的或缺乏必要技能的开发人员通常被要求“跟随”几名主要的On-Call轮值人员,以了解情况。

“你最好的能力是随时响应。”这句老话是成功On-Call的关键。

一般来说,人们希望On-Call工程师能做出快速反应,但不一定需要快速解决问题。

创建一个你在紧急情况下可以依赖的资源清单:可以直接链接到你的服务的关键仪表盘和运行手册、访问日志的说明、重要的聊天室,以及故障排除指南。创建一个单独的“On-Call”书签文件夹,并保持更新,这会很方便。与团队分享你的清单,以便其他人可以使用和改进它。

有些支持请求异常紧急,而有些请求则在一周内完成就可以。如果你无法判断一个请求的紧急程度,请询问该请求的影响是什么。影响范围将决定优先级。如果你不认可请求者对于某个问题的优先级次序的看法,请与你的管理者讨论一下。

谷歌云的支持优先级梯队提供了一个如何定义优先级的例子(你可以在谷歌云的技术支持页面找到相关说明)。 ● P1:严重影响(critical impact)——服务在生产环境中无法使用。 ● P2:高影响(high impact)——服务的使用受到严重损害。 ● P3:中等影响(medium impact)——服务的使用部分受损。 ● P4:低影响(low impact)——服务完全可用。

为了可以清晰地进行沟通,要有礼貌、直接、反应迅速,并且彻底。

在一连串的运维任务和干扰之下,开发人员会感到压力和变得暴躁——这是人的本性。在对支持任务进行回应时要有耐心和礼貌,虽然这可能是你一天中的第十次被迫中断,但这可能是请求者与你的第一次互动。

简洁确保你的沟通容易被阅读和理解。如果你并不知道答案,就说出来;如果你知道答案,就大声说出来。 回应请求要迅速。回应不一定代表解决方案。告诉请求者你已经看到了他们的请求,并确保你理解问题所在。

2024/2/17 发表想法 之前也有写过这个解决方案手册,把所有遇到的问题及解决方法沉淀下来,方便自己成体系的思考问题,反思自己,避免类似的问题发生或举一反三吧,也可以给他人提供资料参考。就好像读书时候的错题本一样,但可惜没有坚持到现在😓

在工作过程中,通过在每个任务票中写下更新内容来跟踪进度。在任务票中包含缓解或解决该问题的最后步骤,这样,如果该问题再次出现,你就会有解决方案的记录。

在工作过程中,通过在每个任务票中写下更新内容来跟踪进度。在任务票中包含缓解或解决该问题的最后步骤,这样,如果该问题再次出现,你就会有解决方案的记录。

始终在你的笔记中包含时间戳。时间戳有助于操作人员在调试问题时将整个系统的事故联系起来。当用户在下午1:05开始报告延迟时,知道某项服务在下午1点被重新启动了是很有价值的。

事故响应分为以下5个阶段。 ● 分流(triage):工程师必须找到问题,确定其严重性,并确定谁能修复它。 ● 协同(coordination):团队(以及潜在的用户)必须得到这个问题的通知。如果On-Call人员自己不能解决这个问题,他们必须提醒那些能解决的人。 ● 应急方案(mitigation):工程师必须尽快让事情稳定下来。缓解并不是长期的修复,你只是在试图“止血”。问题可以通过回滚一个版本、将故障转移到另一个环境、关闭有问题的特性或增加硬件资源来缓解。 ● 解决方案(resolution):在问题得到缓解后,工程师有一些时间来喘口气、深入思考,并为解决问题而努力。工程师将继续调查问题,以确定和解决潜在的问题。一旦眼前的问题得到解决,事故也就得到了解决。 ● 后续行动(follow-up):对事故的根本原因——为什么会发生,进行调查。如果事故很严重,就会进行正式的事后调查,或进行回顾性调查。建立后续任务,以防止那个(或那些)根本原因的再次出现。团队要寻找流程、工具或文档中的任何漏洞。在所有的后续任务完成之前,相应事故的处理不应该被认为已经结束了。

你在应急方案的阶段目标是降低问题的影响。应急方案并不是要彻底地解决这个问题,而是要降低其严重性。修复一个问题可能需要很多时间,而应急方案通常可以很快完成。

对于小问题,线性搜索即从前到后检查组件是可行的。在更大的系统上使用分片检索或二分法搜索(也称为半分法),即在调用堆栈的一半的位置上设置一个断点,看看问题是在上游还是在下游。

处理事故的On-Call工程师会负责起草一份回顾总结的文档,其中应记录发生了什么、学到了什么,以及需要做什么来防止事故再次发生。

任何回顾总结文档的关键部分是根本原因分析(root-cause analysis,RCA)。根本原因分析是利用5个“Why”进行的。这种技巧非常简单:不断地追问为什么。

2024/2/17 发表想法 一个好的团队氛围不应该是出了问题互相甩锅指责的,特别是别让会议变得批斗大会一样。有问题大家一起讨论解决,别人做的不够好的地方说出来,一起怎么更好的处理问题避免类似情况发生,一起互相学习共同进步才是

在面临高压的情况下,人们很容易生气和互相指责。尽你所能提供建设性的反馈,指出需要改进的地方,但避免指责个人或团队的问题。“彼得没有禁用消息头”是一种指责,而“消息头配置的改变没有经过代码评审”是一个需要改进的问题。不要让事后的总结会变成不健康的发泄会。

在面临高压的情况下,人们很容易生气和互相指责。尽你所能提供建设性的反馈,指出需要改进的地方,但避免指责个人或团队的问题。“彼得没有禁用消息头”是一种指责,而“消息头配置的改变没有经过代码评审”是一个需要改进的问题。不要让事后的总结会变成不健康的发泄会。

由于你“真正的”工作是编程,参与到支持工作中可能会让你分心。把支持工作看成一次学习的机会,你会看到你团队的软件是如何在现实世界中被使用的,以及它失败或使用户感到困惑的方式。

而依赖“救火队员”的团队不会拓展自己的专业知识和提高排除故障的能力。“救火队员”的英雄主义也会导致那种修复严重的潜在问题的工作被置于次要地位,因为“救火队员”总在旁边修修补补。

行为准则 

◆ 第10章 技术设计流程

设计工作被分成两种活动:单独的深入思考和协作的小组讨论。研究、头脑风暴和写作构成了深度工作。设计讨论和对设计文件的评论构成了合作的部分。这个过程的有形产出是一份设计文档。

 图10-1 设计过程的螺旋式上升

你现在处于圆锥体的顶部。你在你的设计中已经投入了大量的工作,而且对你的方案充满信心。你将设计方案在整个组织内传阅。安全、运维、相关的团队和架构师都需要了解你所承诺的变更,这不仅仅是为了提供反馈,也是为了更新他们对整个系统工作方式的心理模型。

你的首要任务是定义和理解你要解决的那个(或那些)问题。你需要了解问题的边界,以便知道如何解决它,并避免构建错误的东西。

你提出的设计不应该是你的第一个想法,而应该是你若干想法中最好的那个。

最后,你应该批判性地思考。不是所有你在网上读到的东西都是好主意,一个特别常见的错误做法是将一个与你的问题相似但不完全相同的解决方案全盘复制。你的问题不是谷歌的问题(即使你在为谷歌工作),尽管它们看起来很相似。

不要迷恋你的实验性代码。概念验证类的代码是为了说明一个想法,然后被扔掉或重构,把你的精力集中在说明或测试你的想法上。不要写测试,也不要花时间打磨代码。你要尽可能快地学习到更多的东西。

你不会在你锁定的整段时间内进行“设计”。你的大脑需要时间来放松:休息一下,给自己一个呼吸的空间;允许你的思想放松和游荡;去散步、泡茶、阅读、写作、画画。 设计是一种每天24小时都在进行的工作,所以要有耐心。你的大脑总在酝酿着各种想法,创意想法会在一天内随机出现(甚至在你睡觉的时候)。

如果没有指导方针,就用这3个标准来决定是否需要设计文档。 ● 该项目将需要至少一个月的工程时间。 ● 这一变更将对软件的扩展和维护产生长期的影响。 ● 该变更将显著影响其他团队。

设计文档是一种工具,可以帮助你思考、获得反馈、让你的团队了解情况、培养新的工程师,并推动项目规划。

2024/2/17 发表想法 写作的好处非常多,三言两语说不清楚。但却很少人意识到这一点,也许写作需要花费更多的时间和精力吧,还好我能坚持写工作相关文档和自己的技术博客,回过头看确实受益良多

写作拥有一种暴露你不知道的东西的能力(在这一点上请相信我们)。迫使你自己写下你的设计,迫使你去探索问题空间,并使你的想法具体化。你将不得不面对其他的方法和理解上的差异。这是一个动荡的过程,但是经历了这个过程,你会对你的设计和它的权衡有更好的理解。通过写下你的设计,你会得到清晰的思路,也会使设计讨论更有成效。

写作拥有一种暴露你不知道的东西的能力(在这一点上请相信我们)。迫使你自己写下你的设计,迫使你去探索问题空间,并使你的想法具体化。你将不得不面对其他的方法和理解上的差异。这是一个动荡的过程,但是经历了这个过程,你会对你的设计和它的权衡有更好的理解。通过写下你的设计,你会得到清晰的思路,也会使设计讨论更有成效。

写作作为一项技能,就像其他技能一样,是通过实践来进步的。充分利用写作的机会——设计文档、电子邮件、代码评审意见——努力写得清晰。

设计文档应该描述当前的代码设计、变更的动机、潜在的解决方案,以及建议的解决方案。该文档应该包括建议的解决方案的细节:架构图、重要的算法细节、公共API、模式、与替代方案的利弊比较、假设和依赖项

如果你的团队有模板,请使用他们的模板;如果没有,请尝试下面这种结构,我们将详细介绍: ● 概要; ● 现状与背景; ● 变更的目的; ● 需求; ● 潜在的解决方案; ● 建议的解决方案; ● 设计与架构; ♦ 系统构成图; ♦ UI/UX变更点; ♦ 代码变更点; ♦ API变更点; ♦ 持久层变更点; ● 测试计划; ● 发布计划; ● 遗留的问题; ● 附录。

设计与架构应该包括组件的示意图、调用流和数据流、用户界面、代码、API和模式模拟。

不要让人惊讶 你需要有礼貌地并且渐进地让人们了解你的设计方案。如果正式的设计文档是其他团队和技术负责人第一次了解你的工作,你就是在为自己的失败埋下伏笔。每一方都有不同的视角和不同的利益诉求,他们可能会对一份突然出现的、他们没有发言权的设计文档做出强烈的反应。

反馈会议不需要是正式的,也不需要专门来安排。在午餐时、在走廊上,或在会议开始前的随意交谈都可以,甚至这都是应优先选择的方式。你的目标只是让人们意识到你在做什么、提供一个反馈的机会,并让他们思考你的工作。

设计讨论可帮助你理解问题空间、分享知识、讨论利弊,并巩固设计

行为准则 

◆ 第11章 构建可演进的架构

。你可以通过构建可演进的架构来适应不断变化的需求。可演进的架构可避免复杂性,复杂性是演进性的敌人。

复杂系统有两个特点:高依赖性和高隐蔽性。我们要再加上第三个:高惯性。

高依赖性导致软件依赖于其他的API或代码行为。依赖性显然不可避免,甚至是可取的,但必须取得平衡

高隐蔽性使得程序员很难预测某项变更的副作用、代码的行为方式,以及需要修改的地方。晦涩的代码需要更长的时间来学习,开发人员更有可能在无意中破坏某些东西

高惯性是我们在奥斯特霍特的列表中加入的新特点,是指软件保持之前的使用习惯。用于快速实验且很容易被丢弃的代码具有低惯性,一项为十几个关键业务应用提供驱动力的服务具有高惯性

面对未来未知的需求,工程师们通常会选择下面两种策略中的一种:试图预判未来的需求,或者建立抽象模型作为逃生舱门,使后续的代码修改更容易。不要玩这种把戏,两种策略都会导致复杂性提高。要保持事情简单一些(被称为KISS的原则——保持简单、愚蠢)。

YAGNI是一种看似简单的设计实践:不要构建你不需要的东西。

避免过早优化,避免不必要的灵活抽象模型,以及避免最小可行产品(minimum viable product,MVP)所不需要的产品特性——你需要那些可以获得用户反馈的最低限度的功能集。

过早优化是指开发人员在证明需要优化之前就对代码进行性能优化。

保持代码灵活性的最佳方法之一是减少代码的总量。对于你所构建的一切,问问自己哪些是绝对必要的,其余的就舍弃掉。

随着经验的增长,你会更善于预测何时需要灵活性和优化。同时,在你怀疑可以插入优化的地方放置接口填充程序,但不要真正实现它们。例如,如果你正在创建一个新的文件格式,并且怀疑你以后会需要压缩或加密,那么就提供一个指定编码的头信息,但是只实现未压缩的编码。这样你可以在未来添加压缩算法的实现代码,而头文件将使新代码很容易读取旧文件。

识别领域边界和封装领域知识既是一门科学又是一门艺术。有一种完整的架构方法叫作领域驱动设计(domain-driven design,DDD),它定义了一套广泛的概念和实践,将商业概念映射到软件上。

完全向后兼容和向前兼容的变更意味着API的所有的历史版本和未来版本都可以相互操作。这可能很难维护,会产生像处理废弃字段逻辑这样的棘手问题

行为准则 

◆ 第12章 敏捷计划

个人和互动高于流程和工具 工作的软件高于详尽的文档 客户合作高于合同谈判 响应变化高于遵循计划

看板不像Scrum那样使用固定周期冲刺。相反,看板定义了工作流程中的各个阶段,所有的工作条目都要经历这些阶段(例如,待着手、计划中、实施中、测试中、部署、展开)。

用户故事是一种特殊的任务票,它从用户的角度定义了特性的需求,格式是“作为一名<用户>,我<想><这样>”

站会通常是在每天早上安排15分钟的会议(快到可以站着完成,不过实际上可以选择是否一定要站着)。在会议上,队友们围成一圈,介绍自上一次站会以来他们所做的工作,他们计划在未来做什么,以及他们是否发现了任何可能拖延或破坏冲刺进程的问题

状态应该被快速更新,这并不是一个排除故障的地方。尽量将你对进展的评论限制在最基本的范围内,并提出你有的任何问题。也要宣布你的发现:你发现的bug、软件的意外行为等。可以在稍后的停车场讨论中谈谈你的发现(当然不是在真正的停车场)。

评审是为了庆祝团队的胜利、创造团结、提供反馈的机会,并使团队对进展保持诚实。在一个团队中,并不是所有的开发人员都在做同样的项目,所以评审可以帮助团队成员了解其他人正在做的事情。评审让队友保持同步,让每个人都有机会提供反馈,并认可杰出的工作,可创造凝聚力。项目状态评审也可以帮助团队就什么是真正的“完成”以及他们如何朝着目标前进达成一致,发现的问题可以在冲刺回顾会上讨论

在回顾会中,团队聚在一起讨论自上次回顾会以来有哪些进展,哪些不足。会议通常分为3个阶段:分享、确定优先级和解决问题

2024/2/17 发表想法 虽然说计划赶不上变化,但有计划和无计划会导致两种截然不同的结果

路线图应该鼓励每个人对团队正在构建的东西进行长期思考,它并不是要成为关于团队9个月后将构建的东西的静态和不可变的文档。更远的地方应该更模糊,而更近的地方应该更准确

路线图应该鼓励每个人对团队正在构建的东西进行长期思考,它并不是要成为关于团队9个月后将构建的东西的静态和不可变的文档。更远的地方应该更模糊,而更近的地方应该更准确

行为准则 

◆ 第13章 与管理者合作

与你的管理者构建工作关系将有助于你发展你的职业生涯、减少压力,甚至交付可靠的软件。与你的管理者合作需要相互了解。你必须了解你的管理者需要什么,这样你才能帮助他们。同样地,你的管理者也必须了解你的需求,这样他们才能帮助你。

管理者们通过与高管或董事(“向上”)合作、与其他管理者(“横向”)合作以及与他们的团队(“向下”)合作来“管理”所有的这些事务

一对一面谈(1∶1)和进展、计划与问题(progress-plans- problems,PPP)报告用于沟通和更新项目状态,而目标和关键结果(OKR)以及绩效评估则管理目标和成长

你应该制定议程,并在一对一面谈中承担大部分的谈话。在面谈之前,与你的管理者分享一份议程摘要。保存一份包含过去议程和笔记的面谈文档,与你的管理者分享你的文档,并在每次一对一面谈之前和之后更新它。如果你的管理者有某些话题要讨论,他们也可以添加自己的条目,但管理者的议程应该排在你的议程之后。

一对一面谈创造相互理解和联系。谈论一些看似无关紧要的话题很正常——你的猫、你的管理者对彩色运动鞋的喜爱或者天气。你正在努力建立一种关系,这种关系比用代码换取薪水更深入。个人和非主题的谈话很重要,但不要让每次一对一面谈都成为一次社交拜访。

PPP中的每个P(进展、计划与问题)都有自己的小节。每个小节应该有3到5个要点,每个要点应该很简短,只有1到3个句子。

OKR框架是公司定义目标和衡量其是否成功的一种方式。在OKR框架中,公司、团队和个人都定义了目标(目的),并为每个目标附上衡量标准(关键结果)。每个目标都附有3到5个关键结果,它们是标志着目标达成的具体指标。

OKR从公司的高层通过团队一直流向每个人。每个人的OKR都有助于实现其团队的目标,而每个团队的OKR都有助于实现公司的目标。

不要把关键结果变成待办事项清单。它们不应该说明如何做某件事,而应该说明你知道如何衡量某件事已经完成。

一个良好的OKR可以让我们在需要做出选择的时候自由地选择正确的方法,而不是在我们设定OKR的时候就提前做好选择。

OKR通常是按季度设定和评估的。与你的管理者合作,了解公司和团队的目标,使用更高阶的目标来定义你的OKR。尽量减少OKR的数量,这将使你保持专注。每个季度有1到3个OKR是一个合理的数值。如果超过5个,你就会把自己搞得过于疲惫。

绩效考核会使用一个工具或像下面这样的模板来进行。 ● 你今年做了什么? ● 今年有什么事情进展顺利? ● 今年有什么事情可以做得更好? ● 你在职业生涯中想得到什么?你认为自己在3到5年内会到达什么样的高度?

试着把考核看作一次机会:回顾你所取得的成果、谈论你接下来要做的事情、公开承认错失、制定下一年的成长计划,并向你的管理者提供反馈。你不应该对你的绩效考核的反馈感到惊讶,如果你感到惊讶,请与你的管理者讨论沟通上的偏差。一份成功的绩效考核应该给你具体的行动来实现你的目标。

2024/2/18 发表想法 辩证性思维看待,得有自己的判断力,选择对自己有改善的接受

不要听信表面上的反馈。你的管理者仅仅是视角之一(尽管是一个重要的视角),试着把管理者的反馈纳入你的观点,而不是直接采用管理者的反馈

好的管理者希望从他们的团队中获得反馈。管理者们需要了解事情的进展——哪些是有效的,哪些是无效的。团队中的每个人都会有独特的观点,反馈可消除盲点

在提供反馈时,使用情况、行为和影响(situation-behavior- impact,SBI)框架。首先,描述情况。然后,描述行为:你认为值得表扬的或有问题的具体行为。最后,解释影响:该行为的影响以及它的重要性

2024/2/18 发表想法 机会一直都有,但如何发现机会、争取机会、利用机会为自己成长添砖加瓦,每个人都有自己的选择吧

请认识到机会以多种形式而存在:新项目、新挑战、要指导的实习生、演讲机会、要写的博客文章、培训,或要合作的团队。在正确的视角下,你做的每件事都是成长的机会。

请认识到机会以多种形式而存在:新项目、新挑战、要指导的实习生、演讲机会、要写的博客文章、培训,或要合作的团队。在正确的视角下,你做的每件事都是成长的机会。

如果你已经给出了反馈意见,并保持了耐心,但事情仍然没有进展,那就起身离开。

行为准则 

◆ 第14章 职业生涯规划

资深工程师所应具备的技术能力、执行能力、沟通力和领导力。重要的是,资深工程师的工作范围和重点也会发生变化。初级工程师实现特性和完成任务,而资深工程师要处理更多的不确定性和模糊性。他们帮助确定工作内容、应对更大或更关键的项目,并且需要更少的指导。

T型人才描述为: ……这些人既是通才(在一系列广泛的有价值的事情上有很高的技能——T的顶端横线),也是专家(在某个垂直领域中成为佼佼者——T的竖线)

一个好的团队会有一个坚实的T型人才的组合。产品开发团队的成员有可能拥有不同的深度领域,而基础设施团队的成员则更有可能拥有共同的专长。

了解晋升的流程,确保你的工作是有价值的和可见的,当你认为自己接近下一个级别时,要大声说出来。

说到晋升谈话,时机很重要。在你认为你已经准备好晋升之前,大约在你达到一半的时候,就开始这些谈话。尽早参与,使你和你的管理者都有时间进行协调并解决差距问题。如果你已经拖到了你认为你应该得到晋升,但你的管理者并不同意的时候,晋升谈话就会变成如何解决冲突,而不是提出一个计划。

塔尼娅·赖利的演讲和博文建议,如果你的管理者不认为你贡献的价值是晋升的途径,你就不要再做胶水工作了——即使它会在短期内伤害团队。这让人如鲠在喉,而且可能看起来不公平,但是让事情公平的责任在管理层,而不在你。

“邻家芳草绿,隔岸风景好”

如果你仍然有适当的薪酬、成长和学习,就请坚持你现在的工作。看到团队、公司和软件随着时间的推移而不断发展是非常有价值的。