为亚马逊编写代码是什么样的体验(第一部分)
去年我写了几篇关于我的“亚马逊之旅”的文章。你可以在这里阅读:https://dev.to/bytebodger/how-i-got-hired-at-amazon-3ajl和这里:https://dev.to/bytebodger/what-its-like-to-code-for-amazon-4nke。我的亚马逊“职业生涯”持续了整整10个月。1月18日,亚马逊解雇了18000名员工。我就是其中之一。
几个月来,我一直在犹豫要不要写这篇文章。最初几次尝试写的时候,感觉太过苦涩,而且会给人一种“酸葡萄”的感觉。所以我把那些初稿都删掉了。但现在,离开亚马逊几个月后……我觉得是时候了。
我得坦白说。这篇文章基本上就是我自己的疗愈。如果你觉得它不够“专业”,或者你想跳进评论区嘲笑我的观点,好吧……我真的不在乎。你可以写一篇博文,说我是个白痴,或者说所有被亚马逊抛弃的人都是罪有应得,或者说这一切都是“世道”。但这是我的文章。我会根据我的亲身经历来解释。
摊牌
在深入细节之前,我想坦诚地说明几个关键点。首先,我的经历并不能代表亚马逊的整体情况。这家公司规模庞大。即使在裁员之后,他们的员工队伍仍然庞大。亚马逊的员工人数仍然超过一百万。即使我们剔除所有非程序员,员工队伍仍然庞大。所以,如果你曾经在亚马逊工作过,或者现在在那里工作,你的经历可能与我完全不同。
其次,我可以坦诚地告诉你,我“全力以赴”。我真心希望亚马逊是我最后一家雇主。我真心希望它能成功。所以,我加入亚马逊并非为了“兴风作浪”。
第三,在这种情况下,很容易把矛头指向全公司裁员,并坚称我的离职与我无关。毕竟,他们已经裁员18000人(而且刚刚宣布即将裁员9000人)。所以我很容易会想起那些安慰人心的陈词滥调,说我是更广泛市场力量的受害者。但这种说法……是错误的。
我的团队里其他人都没被释放。我被单独挑出来了。从2022年11月到2023年1月,这让我承受着极大的精神痛苦。
那么,到底出了什么问题?让我们深入探讨一下……
生活在岛上
在软件工程领域工作了二十五年,我从未在任何一家公司像在亚马逊那样有这种感觉。感觉就像在一座孤岛上工作。我被招入了一个后端开发团队,他们习惯于只用 Java 工作。需要说明的是,这没关系。我自己就是 Java 开发人员。但我是专门被雇来开发前端应用程序的。
我的团队里竟然没人能告诉我如何在本地运行我们的应用。真的没人。你可能会想:“嗯……这有什么难的npm start
?” 但是你根本没法用npm start
或yarn
或其他任何前端开发者常用的工具来运行我们的前端应用。
我刚加入的时候,仓库里有一系列说明,教你如何让应用运行起来。这些说明根本没用。一点用都没有。我甚至花了几周时间才弄清楚如何在测试环境中运行应用。而且我不得不自己摸索,因为当我(反复)联系团队里的其他开发人员,想弄清楚如何让它运行起来时……他们却一无所知。
即使我成功运行了它,“默认”配置也是在 EC2 实例(内部称为“云桌面”)上运行所有内容。这或许没什么问题。毕竟,我以前也用过 EC2 实例。但让它在 EC2 上运行的唯一方法是对整个应用(也就是前端和后端代码)进行完整的编译和推送,每次我想测试我的更改时都要花13 分钟。
团队里的其他人似乎都觉得这只是“例行公事”。他们似乎无法理解,为什么当我得知每次代码修改都要花13分钟来验证时,我会如此恼火。
诚然,我最终确实找到了如何将本地环境实时同步到 EC2 实例的方法。但这花了我很长时间才搞定。同步运行后,大约 10 秒就能在 EC2 实例上看到我的更改。但我不得不自己摸索,因为现有的文档都没有提供任何关于如何实现这一点的线索。
搞清楚之后,我把所有步骤都记录了下来,这样以后的开发人员就不用再经历我之前头疼的问题了。但我已经能感觉到,我的经理哈迪克对我高效编写新代码的延迟越来越恼火了。
即使没有任何有意义的指导,如果我不是在 Windows 电脑上工作,我的高效开发之路也会顺利得多。入职时,在入职前几周,我收到一封电子邮件,询问我想要 Mac 还是 Windows 电脑。虽然我以前用过 Mac,但我在 Windows 上的工作量总是更大(是的,我知道,这种情况很不寻常),所以我干脆回答说我想要一台 Windows 电脑。这真是个大错误。
所有亚马逊内部文档都假设你使用的是 Mac 电脑。即使我将许多命令从 Bash 翻译成了 PowerShell,我仍然遇到了许多令人抓狂的难题。他们希望你使用的很多命令行实用程序根本无法在 Windows 电脑上运行。虽然我最终解决了所有问题,但在工作了几个月后,我终于开口说道:“你们能给我寄一台 Mac 吗?”
公平地说,他们确实给我寄了一台Mac。但那时,Hardik已经把我看作一个落后的人了。
外包
当我终于能够高效地在这种环境下编写代码时,我立即被派往另一个团队,负责一个短期、高优先级的项目。当然,这个项目还有一整套繁琐的设置要求。
我是这个新项目的唯一前端开发人员。他们介绍我参与这个项目时,还让我参考了代码库——但它甚至编译不出来。事实上,我和团队负责人 Shawn 开了个电话会议,他花了好几个小时才让这个应用在本地运行起来。
在我们进行这些会议的时候,Shawn 反复向我道歉,抱怨项目的现状。他还多次告诉我,他们可能还没准备好让前端开发人员来负责这个项目。但我仍然被期望快速完成前端代码。
他们正在开发一个全新的应用。但管道配置为仅接受符合 ES5 标准的 JavaScript。当我向他们提出这个问题,并认为这是一个重大的危险信号时,他们完全无法理解,为什么我在 2022 年用var
JavaScript 以及 ES5 的所有其他古老标准编写全新的代码会遇到问题。
那些编译问题在我第一次成功运行应用程序后并没有消失。第二天我就开始工作,代码什么都没改,却发现应用程序又一次编译不通过。它编译不通过的原因是后端开发人员不断修改应用程序的关键参数。但这些参数并没有全部被纳入一个可靠的变更集。所以,即使应用程序昨天运行良好,第二天早上我拿到最新版本后……什么都没用。
每当这种情况发生,我就会和 Shawn 开电话会议,即便如此,他仍然需要花费数小时才能将最新版本编译到可以顺利通过的程度。他还会一直向我道歉。他还一直告诉我,他们实际上甚至还没准备好让前端开发人员来处理代码。但我仍在继续这个项目。几乎每天都会遇到同样的问题。
即使项目能够运行起来,弄清楚到底要写什么代码仍然让我抓狂。他们不停地告诉我,必须为来自后端的某些变量编写代码。但这些后端服务还远远没有完成。他们甚至连一个数据模型都给不了我。我简直就是盲写代码。
我每隔几天就会和我的经理哈迪克开一次会。每次我都告诉他,这个项目简直就是一场噩梦,在他们解决后端问题之前,我根本就不应该参与这个项目。哈迪克也同意我的看法。
我还反复告诉团队负责人肖恩,几个月后再回来做这个项目,我的时间会得到更好的利用。他也同意了我的建议。但我花了一个多月的时间才正式说服自己退出这个项目。
尽管我的原经理哈迪克和二级项目团队负责人肖恩都承认了这些问题,但几个月后,我却得知有人向高层汇报,说我“难以共事”。这简直是背叛。但我尽量不去在意,因为当我收到这个消息时,我已经被调回原来的团队了。
重返保留地
至此,我已经成功完成了团队前端应用程序开发中极其棘手的流程。我也熬过了临时外包项目的噩梦。但很明显,我的经理哈迪克觉得我落后了。
我和他开了个会,他建议我应该专心于我们主应用(名为“Sonar”)的代码开发。他特别建议我争取在下个月提交 10 个拉取请求。
我完全同意他的观点,然后泰然自若地投入到我们的“日常”工作中。事实上,在接下来的一周里,我提交了超过10个拉取请求。但从那时起,他就一直在谈论我,好像我没做多少工作似的。
这种情况持续了好几个月。实际上,我甚至向他展示了我的git
提交记录、拉取请求历史记录和已完成的工单,证明我完成的工作量是团队中其他人的四倍多。但他似乎根本没意识到这一点。他总是当着我的面,以及在小组会议上谈论我,就好像我似乎总是无法交付成果一样。
我不是唯一一个注意到哈迪克与现实脱节的人。我们团队里有一位高级架构师安迪。他经常在Slack上跟我倾诉他对哈迪克的不满。他告诉我,他已经把这些不满汇报给了我们的主管。他还鼓励我提交一份关于我自身经历的报告。然而,我没这么做,因为那时我才刚来公司五个月左右,而且我真心觉得,一个新人向主管抱怨他的经理,不太“体面”。
回滚队长
我很快发现,Hardik 也是个“回滚队长”。我们的代码库里,有一些老掉牙的单元测试,几乎毫无用处。(另外,一个有趣的事实:没人知道如何运行它们,而且它们根本没法连接到部署流水线。)就算你知道怎么运行它们(我就懂),它们也只覆盖了应用很小的一部分,根本没用。
我们的应用程序中有很多重要部分,团队中甚至无人知晓如何使用。因此,在毫无价值的测试“覆盖率”和完全缺乏相关知识的情况下,测试更改的唯一真正方法就是将其推送到 EC2 环境并进行手动检查。但由于缺乏足够的应用程序端到端知识(实际上没有人具备),手动测试只能是碰运气。
也许正是因为这些因素,Hardik 成了回滚队长。每当在本地代码执行环境中发现任何 bug(无论多么微不足道),他的第一反应总是回滚代码。当然,当你刚刚部署到生产环境并发现 bug 时,我完全理解这种冲动。或者,如果你近期有待部署的生产环境,我也能理解这种冲动。
但如果我写的任何东西有任何问题——无论问题多么微不足道——他从来不会问要怎样才能简单地解决这个问题。他立刻就想回滚。
有好几次,在生产环境中发现 bug 后,他想回滚我在本地代码引擎 (LLE) 中的最新更改,即使我的更改尚未部署到生产环境中。还有几次,他想回滚我的代码,即使我所做的更改与发现的 bug 根本无法想象有任何联系。
而且我并不是唯一一个告诉他这一点的人。团队里其他经验更丰富的开发人员也会告诉他同样的事情。但这无关紧要。任何观察到的bug都会导致Hardik立即下意识地要求我回滚最新的更改。
地狱计划
尽管我和 Hardik 之间一直存在一些“问题”,但我仍然决心要交出扎实的工作。而这份“扎实的工作”体现在一个必须在 Sonar 中实现的大型新项目上。
需要说明的是,这个“大型新项目”一开始看起来并不像个什么大项目。我们进行了冲刺规划,我指出我的任务大概需要几周时间。我当时是根据我对这个应用程序(以及新要求的功能)的了解程度来估算的。但在早期阶段,有很多需求我根本无法理解……
我们采用了持续部署模型。尽管我的项目部分看起来很小,但整个工作显然需要几个月的时间。所以,当我开始规划如何完成我的项目部分时,很明显我不能提前提交它们——因为如果我这样做,它们会被部署到生产环境中,然后就会因为后端部分尚未完成而崩溃。
我和我们的架构师 Andy 讨论了如何处理这个问题。在讨论了几个方案之后,我们都同意应该在功能标志下部署这个问题,这样我的新代码就不会在完整项目发布之前破坏任何东西。
然后我问他:“你能告诉我代码库里哪些地方我们已经使用了功能开关,这样我就可以按照同样的方法操作吗?” 他回答说代码库里没有现成的功能开关功能。这没问题。我开始构建一个新的功能开关系统。但这当然让我的最初估计被打乱了。
当然,我在整个过程中都与团队进行了充分沟通。我创建了新的工单来跟踪功能开关的开发。几乎每次站会,我都会反复向团队通报修改后的时间表。我还将功能开关功能设计为“通用”的,使其高度可配置,可以用于 Sonar 未来可能需要的任何条件功能。然而,Hardik 并不满意。
转变数据模型
功能标记功能到位后,我开始编写项目最初的需求代码。前端功能表面上看起来相当简单。基本上,我们只需要考虑来自 API 的一些新值。最初,我以为会有人修改 API。但最终我意识到我需要自己动手。这……也还好。但这从来都不在我最初的预估之内。
因此,我创建了新的工单来跟踪 API 的更新。我在站立会议期间反复向团队传达了这一切。然后,我编写了 Java 更新代码,以提供所需的值。
直到我完成这些之后,Andy 才告诉我,我的数据模型“无法工作”。这很难解释,但可以肯定地说,在他们奇怪的数据模型中,我需要根据 API 返回的一组非常复杂的其他变量来推断值。当然,我在最初进行估算时根本不知道这一点。
在我编写了一套新的 Java API 来处理我推测的新变量之后,Andy 告诉我,他将开发一套他自己的 API 供我使用。这意味着我之前编写的 Java API 工作白费了。这也意味着我编写的前端代码(假设它会接收我编写到 API 中的值)必须完全重写。他也无法提供任何我可以用来编写新前端代码的假定模拟数据。换句话说,我只能等着他告诉我新数据是什么样子。
在站立会议期间,我反复向团队传达了所有这些信息,并且在不了解数据模型的情况下,我做了尽可能少的前端编码。
与此同时,安迪不断向我诉说他对哈迪克糟糕的管理有多么失望。事实上,有一天,他安排了一次与我的单独会面,告诉我他要调往另一支球队。会面期间,他还对我说:“如果你想转会,尽管告诉我。我很乐意再次与你合作。”
截止日期至高无上
我们原本计划在十月中旬交付这项新功能。我们之前计划在10月1日左右在我们的本地语言引擎(LLE)中实现这项功能,以便开始测试。最终,我在11月30日星期五收到了一个数据模型的样机,我需要根据这个模型来编写我的功能。
到了10月3日星期一,Hardik 已经焦躁不安了。他试图每小时给我发一次邮件,告诉我作品的完成时间。我当时正在快速地编写代码,也做了不少“前期工作”。但对于那些依赖于一个工作日前才拿到的数据模型的功能,我能做的却非常有限。
到了周二晚上,Andy 在 Slack 上联系我,告诉我 Hardik 会调动一大批其他开发人员参与进来。大概是为了实现我之前没能完成的功能。(再说一次,这些功能我其实是上周五才真正完成的。)
接下来的一周,我浪费了大量精力。我们有四个不同的开发人员,编写了多个功能,但这些功能都保存在同一个代码文件中。很多时候,我提交 PR 时,却发现其他人已经提交了他们自己版本的功能。我们所有人都在不断地处理合并冲突。
尽管一片混乱,我们还是成功实现了这些功能,并将其推广到本地学习环境 (LLE)。就在那时,我于十月第三周前往西雅图参加了一个团队现场会议。
请继续关注第 2 部分...