作为一名1x开发人员,我在亚马逊五年的工作中总结了20条经验法则,希望能够在有限的自由时间内自我提升为1.1X开发人员。这些经验法则涉及生产力和学习、编程语言、技术、测试、DevOps、安全、设计和项目管理等领域。希望对大家有所启发。
本文最初发布于Mickey Wiki,InfoQ中文站经原作者授权翻译并分享。
我不是一个10x开发人员。自从有了拨号上网以后,我就没有再建过网站。我在大学毕业几年之后才开始学习编程,因为我在政府和政治领域的职业生涯已经走到了瓶颈。
我写了五年代码了,这段时间都在亚马逊。在这期间,我还在养育三个孩子,我刚开始工作时,他们分别是0岁、0岁和2岁。所以我不是那种在晚上和周末还在努力加班的人。我很顾家。
大约一年前,我做了自己的第一个开源项目。这是我的第一个副业项目,它是一个会议网站。
我从来没有系统地从头到尾读过一本关于软件工程的书。
总之,我是一个1x开发人员。我为了体面的生活付出了足够的努力。我没有太多有普遍价值的东西要说,也没有太多时间去提升。
作为一个1x开发人员,我使用的是大量的传统智慧。关于软件工程,我没有太多有趣或新鲜的东西可说。
总的来说,我还没有找到方法去从工作中抽出大量时间,或者去做一些更大的副业项目,或者去大量地阅读,又或者是去取得巨大的成就。我只是能抽点小空(来做这些事情)
但我也有勃勃雄心。我想成为一个1.1x的开发人员。我正在想办法做到。
这篇文章发表的时候,我正好有些比较自由的时间,因为covid-19病毒带来的隔离政策,我能休上几天假,但实际上却哪里也不能去,因为此时孩子们也正在放假。
因此,我打算通过以下方式来自我提升软件工程方面的知识:
言归正传,下面是我作为1x开发人员的经验法则。
据我观察,人类在本质上是个模式寻求者,不断在寻找一种不理性的、前后矛盾的、专制的模式。也就是说,一般来说,大多数人会暗自倾向于以一种取悦领导者的方式设定他们的目标,周围其他人在做什么他就做什么,以及遵循一些现有的模式。在一个复杂的世界中,无论是保持理性还是保持一致性都是非常困难的。因此,“做领导让你做的”或“做同事正在做的”可以信手拈来,又简单又快捷。
这种策略在很多情况下都能起到不错的效果,并有助于营造一种“团队团结”的感觉。但是,当你们的目标涉及外部,要完成一个团队外部的目标时,那么有些事就比“团队团结”更重要了,理性和前后一致地做事是非常有价值的。
我认为经验法则(或者如果想说得高大上一点,可以称它们为原则)可以帮我们提供一些“护栏”、一些“结构”、一些“脚手架”,使大家走出遵从模式的默认心态。它们能帮助我们在一定程度加强逻辑上的一致性。当优先级和价值观发生大量地碰撞时,它们有助于使交流抓住重点。当你试图弄清楚,如何面对无数的选择做出决定时,它们可以帮助你提出一个更清楚明确、更深思熟虑的简便方法。
我就职于亚马逊,它以拥有一套普遍适用的原则而著称,在招聘、做艰难决择、权衡利弊时都会用到这些原则。我认为有了它们,会使公司更好。不是因为它们有什么能人异士,而是因为遵循原则总比倒退到唯领导是从要好。
思考很难,做决定很难。有一些精心思考的规则可以帮助我们更好地指导决策。
尽管如此,下面的经验法则其实与亚马逊的原则并不相似。它们是我通常一想到某个主题时,脑海中就会浮现出的一些经验体会。
我有时会听到有人说,智商测试唯一衡量的是“你有多擅长做智商测试”。我赞成这种看法,也赞成大多数知识都有高度相关性这一普遍看法。大学以来,我做过七份不同的“实际工作”,每一份都有不同职位。在亚马逊,我做过两种完全不同的产品和岗位。
我发现,我从一份工作中学到的东西,有90%对下一份工作完全没有用处。即使这两份工作同属一个职业领域。但也不是全部都没用,剩下的10%可能是非常重要的10%,比如如何更好地处理电子邮件或如何应对办公室政治。但是,当我开始下一份工作的时候,我学到的大部分东西都是“用完就没用了”,即在一个非常特殊的组织下如何以非常特殊的方式来做事。
亚马逊可能截然不同,因为这里的开发人员花费大量的时间来掌握在其他地方根本不存在的内部工具和业务概念。我大概被这弄得有点想不通了。我知道其他开发人员具有不同的体验,他们掌握一种特定的技能,而这些技能实际上可以随着他们从一份工作迁移到另一份工作。
在教育领域(我曾从事过几年这方面的工作),有一个真相是,大多数知识是不可迁移的。学习某个领域的知识通常对其他领域没有帮助。
所以,我常常任性地认为:如果我今天所做的90%的事对未来的工作没有任何帮助,那么我应该不在那90%上投入过多的精力(像我以前那样),例如,去关注些通用的思想、系统、抽象概念和技术,或者出于某种重要原因,我愿意为这份工作牺牲那90%的时间,或许,仅仅是因为钱多。
这条规则对我来说可能比较特殊,因为我换过很多工作。对于其他人来说,他们或许能够将大部分技能从一份工作迁移到另一份工作。
复利是一个非常重要的概念,它存在于利率体系中、摩尔定律中,哪里都有它。它主要是关于良性循环的。因此,在有限的自由时间里,我想的这条经验法则是,把重点放在能够引发良性循环的事情上。
我学会更快地打字是一个完美的开端。在过去两个月时间里,我在keybr.com上花了一些时间学习,它可以很系统地教你如何更快地打字。字打得越来越快让我可以在同样的时间内写更多的东西,进行更多的交流,完成更多的事情,因为这一点改变让我在电脑上做的几乎所有事情都变快了。
建立持久的人际关系也是一项能产生复利的活动,因为它能让你接触到更多的人,他们能帮助你更快地完成工作。
消费媒体(书籍、博客等)并不是一件能产生复利的事情。除非你有某种方法来映射、来消化,将知识融入你的思想。如果这篇文章中有些有价值的东西,除非你做些什么来“加工”它,否则你仅作为读者,可能并不会从中受益。
这部分内容可能会完美地暴露我的无知。
Java是大型企业应用程序的理想选择,很难想象亚马逊在任何其他平台上运行。这是因为它拥有最强有力的类库和社区支持,而静态类型使处理大公司内部的海量数据模型变得更加容易。
我认为C#是微软对Java的一种诠释,如果我需要Java的一些好处,但又身处微软的生态系统中,那么我会使用它。
在我看来,Python和Ruby非常相似,它们都是脚本语言,都是动态类型的,它们似乎是00年代最伟大的东西。当速度比易读性或调试更重要时,就可以选择使用它们。其次,Python非常适用于ML/AI应用。
在使用Python时,你应该使用类型提示,这么做更明智一些。
我认为Go、Rust、Haskell、Erlang、Clojure、Kotlin、Scala是更“硬核”的语言。在这些语言中,我只用Kotlin交付过产品代码。
但是设想一下,如果我正在构建一个延迟和性能比社区或类库支持更重要的全新的Web服务,那么我可能会使用Go或Rust。
我在做一些不需要很多业务逻辑的事情时,比如一些非常优雅的东西或数学函数方法,可能会用到Haskell或Erlang。
我不知道我什么时候会使用Clojure,我想,如果我真的开始了解和喜欢Lisp了,我就会使用它。我知道Clojure是一个编译为JVM字节码的函数范型,但我更喜欢使用Kotlin。因为Kotlin能与Java一起使用,而且IntelliJ对它的支持也很不错。对于Scala也类似,我首先会选择Kotlin。
我写过的最糟糕的代码就是用Javascript写的。当时,我正在为亚马逊做一个移动购物专家,我团队中的同事对于JS框架的有关内容都知之甚少。我们用的是vanilla JQuery。
一开始还很简单,但很快我们就有了很多新的前端需求,管理前端状态简直就是一场噩梦 — 想想看,组件消失了,然后又出来了,我们也不知道为什么,所以我们把每个变量都输出到了控制台。
许多人都有过如此糟糕的经历,我就是其中之一。但我认为这主要是我们自己造成的。几年后的今天,我的JS指南是:
1、使用Typescript ,这是更明智的选择。
2、尝试尽可能将逻辑推给服务器。如果前端不是超级复杂,我将考虑类似于Phoenix的选择,它实际上是把所有东西都推给了服务器。
3、使用Vue之类的框架,或者在需要前端交互时使用React。
4、不要跳过单元测试。
我觉得不是你选择了C,而是它选择了你。有各种应用程序都必须使用C语言,如操作系统、语言设计、底层编程和硬件应用等。
C++很有趣。它似乎非常适用于机器人、电子游戏和高频交易等应用程序,因为在这些应用程序中,没有“垃圾回收”使其性能更优于Java。
出于安全方面的考虑,在亚马逊禁用PHP,但是至少在2020年有大量Facebook和Slack的后端在使用它的继承者Hack。
在写这篇文章之前,我从来没有考虑过何时使用PHP或Hack。也许是因为这在亚马逊是一种禁忌吧。我知道Slack和维基百科都在使用它。Slack的人声称它拥有一个真正对开发人员友好的编程环境,例如,你不需要重新启动本地服务器来查看你改动的内容,而且它有web-native的并发支持。
当我需要每隔一段时间运行一个相对小且简单的代码块时,我就会使用微服务。
当需要执行即时查询和或需要支持ACID和事务时,请选择SQL。否则选择 NoSQL。虽然NoSQL在事务处理方面越来越好,但PostgreSQL(我熟悉AWS Aurora风格)在可用性、扩展性和持久性方面也越来越好,而这些正是NoSQL的传统优势。
在任何时候我都会尝试编写单元测试,只要预计缺陷产生影响,无论多么细微。缺陷的预计影响应该是:缺陷的可能性 × 缺陷的成本。我的做法像是一种逃避,因为我无法精确计算这些值。但是,至少对于我编写的代码和通常给出的需求来说,一般出现代价高昂的缺陷的可能性还是非常大的。
但每个代码块都应该有一个简单的单元测试,从而验证代码是以可测试的方式编写的,这真的非常重要。
但我不是那种认为每一行和每条分支都必须覆盖的人。如果你不相信自己(或他人)能够很好地计算上面的预计影响方程,那么可以考虑采用这种策略。
我将集成测试定义为调用不属于自己的代码的测试,而不是模拟它。
只要我无法信任不属于我的代码时,就会试着写一个集成测试。特别是,如果它可以在我不知道的情况下进行变更时。
我将端到端测试定义为使用我的产品模拟完整的“用户会话”的测试。用户可以是一个人,也可以是另一台计算机,它试图通过与我的代码进行多次交互来完成某些事情。这些通常是规则12中定义的集成测试的超集。
1、当我不完全理解产品是如何工作的,以及不能对一个变更进行充分的单元测试时,我希望有一种方法可以让我更有信心认为我没有破坏任何东西,就像“冒烟测试”。
2、当我需要一些回归测试用例来验证未来重构的功能时。
3、当很难提前预知结果的时候,例如,在做一个复杂的计算时,我想测试一些代码对它们的影响。
第一种情况应该想办法避免,但第二种和第三种情况实际上真的没有办法。
在亚马逊,默认是由你们自己支持自己的代码,因此如果系统中出现严重错误,你们之中的一位同事将被找来日以继夜地工作,直到问题得到解决。
它可能很残酷。但是亚马逊(例如,我现在的团队)和其他公司中都有专门的部门,他们聘请了一名站点可靠性工程师(SRE),由他负责在正常工作时间之外在线解决严重的生产环境问题。
多年在这方面的经历让我开始相信,作为一名程序员,如果实际上还存在下班后要被找来工作的风险,应该始终提倡使用专门的SRE。一个最好的例子是,如果你“继承”了其他人的代码,还得对里面已有的缺陷负责。
可以在不同的时区找些人,通过培训使他们能够支持你的系统,这件事并不难。关键是,要找到给人家的钱。团队中的工程师们需要共同努力向管理层明确表达这一诉求。
信息安全是一项棘手的工作。在某种程度上,博弈论说的是对的,他们必然会因为过于谨慎而犯错。所以我想的这条规则是,你是否至少可以做一些你自己的安全,以避免受到过于严格的限制。
一个典型示例是亚马逊内部wiki迁移的灾难。早在2015年,亚马逊的信息安全团队就禁止在公司内使用PHP了。我们内部的wiki使用的是MediaWiki,而MediaWiki又是用PHP编写的。
Facebook、WordPress和Slack都在使用PHP,而Facebook正在构建简化后的Hacklang来取代它,内部的wiki团队未对这个决定提出任何质疑,只是把这个信息安全指令当成了一条命令来执行。
他们将MediaWiki替换为基于java的替代品XWiki,最终为这个团队花费了4年多的时间,共计24个开发人员,在这些页面不断迁移的过程中,亚马逊几乎所有其他团队都还经受着中断的困扰,而这些损失并未统计在内。如果他们对PHP的禁令有所抵制,或者对Hack做了更多的研究,可能就能避免这场灾难。
有很多会议的目的是“得到批准”或“得到投入”。你应该予以避免,只有在万不得已的情况下才同意这么做。你希望得到的不是“签字盖章”。你希望能够自己做决定,确定需要与其他人达成什么程度的协议。
相反,设计会议或交流应该是寻求建议和回答问题的。
作为在努力交付产品的开发人员和产品经理,我参加过很多估算会议。
大家会说估算是为了规划,它们的目的是算出某项工作需要多长时间,使每个人都可以按此做计划。
在我五年的工作经历中,只记得有一个项目是这样运作的。那是一个非常简单的安卓应用程序,没有外部依赖,没有什么技术复杂度,只有一个本地mySQL数据库和一些视图。
在这个特别的案例中,因为几乎没有未知的东西,所以我们可以做出非常准确的估算。我们可以准确地预测什么事情在什么时候会准备就绪,误差控制在一两天之内,这对我们有很大的帮助,因为硬性期限定得非常紧张。
在我参与过的项目中,这是唯一一个我们可以精确地量化我们的开发速度,并将其向着里程碑推进的项目。
在所有其他项目中,估算的主要目的是施加压力,逼着大家去聊“但你说过只需要5天”,这反过来又迫使大家更快、更努力,或者加更长时间的班,以便在未来不去聊这样的话题。
我本身并不反对压力。但我认为重点是要认识到,这是做估算的主要目的。
硬性期限:如果不能在这个期限前完成,就会对业务造成严重的影响。
软性期限:如果没有在这个期限前完成,有些人可能会有麻烦。
内部期限:这是一个团队内部目标,不会影响团队之外的任何人。
预计完成日期:这是团队对工作将在什么时间完成的当前预测。
我见过很多人因为把这些东西搞混而痛苦不堪。无论什么时候你收到一个期限,都得先问问这是哪一个。当然,通常情况下,内部期限必须保持在正轨上,才能达成硬性期限。但我想告诉大家的是,如果把内部期限当成硬性期限公布出来,是为了迫使大家多加加班。
另一个需要牢记的是:经常会发生一种情况,当一个工程师给出一个预计完成日期时,其他人却把它设定成了硬性期限。千万不要这样做。
当有人说“我们做敏捷”时,对我来说,这是指每两周开一次团队会议。这就是敏捷对于我的全部意义。
有些人可能会弄不清Scrum和看板这两种敏捷“风格”的区别。在我看来,Scrum意味着“你必须在这两周内完成某些事情”。看板则意味着“在两周内做你能做的事情”。如果你不清楚团队遵循的是Scrum还是看板,你要明确表达,应该推行看板。
考虑到估算的难度(参见规则18),Scrum很容易就变成,你不得不加班去完成那两周内安排的事情。
延伸阅读:
https://muldoon.cloud/programming/2020/04/17/programming-rules-thumb.html
领取专属 10元无门槛券
私享最新 技术干货