文章介绍
1.这个颓废的军阀曾经也是闪光的救世主:深度解析黑客帝国的法国人
作者:萨沙
本文章为萨沙原创,谢绝任何媒体转载
萨沙看电影系列第52集
这个颓废的军阀曾经也是闪光的救世主:深度解析黑客帝国的法国人
法国人究竟是什么东西?他曾经也是一个不亚于救世主的程序。
法国人,是黑客帝国的重要人物。
他的身份类似于一个军阀或者领主,盘踞着母体的一角,手下众多。
我们知道法国人的几个地盘:餐厅、城堡、夜总会。
这些地方均被他改造过,母体的特工无法随便攻入。如餐厅地处闹市区,法国人安置了很多炸弹。
如果特工攻入,法国人可以利用钥匙和门的组合,迅速跳跃到城堡、夜总会或者其他地方,随后引爆炸药,炸毁餐厅。
期间,法国人的众多手下,都可以阻挡特工。
这些手下都是很厉害的,同尼奥都可以过几招。
而最初的特工史密斯,被尼奥一脚就踢飞了。
即便第二集的强化特工,被尼奥三拳两脚就打败。
即便特工能够攻入餐厅,法国人早就跑了。
而他在闹市引爆炸药,炸毁一栋楼,会造成母体的重大混乱。
机器人,当然要全力避免这种情况发生。
其实,法国人就是母体早期的程序。
个人认为,法国人也应该是一种协助母体升级的程序。
法国人的存在,形成了母体的一种地下势力。
法国人不会破坏母体,不会支持尼奥一伙,因为他必须依赖母体生存。
所以,法国人坐视看到5代锡安的毁灭,并没有帮助过历代的救世主。
而法国人存在的意义,应该是作为第三方势力,作为机器和人类的缓冲。
大家注意,钥匙人是被法国人的妻子,故意交给尼奥的。
一旦钥匙人被尼奥控制,法国人想要夺回就几乎不可能。
而钥匙人是尼奥可以进入源代码的关键,他就是一个制作秘钥的程序。
通过他制作的秘钥配合专门的大门,可以在母体内跨越空间穿梭。
所以,母体无法让钥匙人到处乱窜,会引起人类的混乱。
母体也无法让特工看守钥匙人,这样太假了。尼奥会怀疑,甚至拒绝进入源代码。
显然,将钥匙人交给法国人,是最好的选择。
所以,法国人是母体的第三方力量,他同机器人有着很多心照不宣的默契。
如果母体真的要消灭他,法国人早就完了。
法国人自己并没有什么作战能力,甚至被崔妮蒂用手枪抵住被迫服软。
法国人的妻子说,最初的法国人很像尼奥,也是一个了不起的人物。
我们按照一代尼奥生存三十多年来计算,前后六代就是接近200年。
也就是说,法国人的寿命至少有200年。
随着时间的流逝,法国人变得颓废和冷漠,只关心自己的利益,对妻子也不屑一顾。
他成为一个喋喋不休,满嘴陈词滥调的家伙。
在母体容忍的范围内,法国人做了很多事情以满足私欲。
如他利用火车人,从被删除程序的回收站中,招募诸如双胞胎兄弟之类的打手。
这些打手为了不被删除,只能为法国人忠心的服务。
他利用小女孩萨蒂作为条件,强迫印度人夫妻盗取了先知的外壳。
他的势力很大,而且知道母体的大部分秘密,尼奥他们也没有法国人懂得多。
不过,法国人不敢同母体作对,只是在自己的地盘内,虚度时光而已。
他甚至当着妻子的面,对一个女食客下了春药,去满足自己的欲望。
那么,法国人的手下吸血鬼、狼人、双胞胎两兄弟和火车人,都是什么东西?
吸血鬼和狼人,都是老旧母体的一些测试程序。
狼人具有强大的力量,吸血鬼则只有用银弹头才能打死。
这些程序短暂出现以后,就被母体删除。
他们的战斗力很强,很适合做打手。
于是,通过火车人,法国人从回收站中将他们偷运出来,到自己的地盘。
火车人是什么东西?
火车人外面是个流浪汉,其实是一个特殊的程序。
他制造了一个地铁站的程序,可以将回收站中已经被删除的程序,偷运到到母体内。
地铁站可以看做是母体和回收站的一个中转站,是火车人创造的。
火车人先将被删除的程序转移到地铁站,随后再通过地铁转移到母体内。
地铁站是火车人创造的,在这里他就是上帝,连尼奥也不是他的对手。
除非火车人愿意,不然普通的程序根本无法从这里脱身。
至于双胞胎兄弟,也是被删除的坏程序。
他们可以瞬移,还可以瞬间修复自己的伤口。
两兄弟是一种失去控制的程序,应该是他们的代码出现了错误。
其实,两兄弟只有一个技能,就是会虚化后穿越空间,比如墙壁、大门甚至地面。
在虚化的时候,他们可以躲避任何攻击,也会将自己受伤的身体重置恢复。
这就是他们的程序出现了问题,没有受到母体三维空间架构的限制。
这属于重大故障,母体很少有程序出现这种问题。
在发现这程序出现大事故时,母体第一时间将他们删除。
而法国人利用火车人,从回收站中将他们救出,成为自己的打手。
两兄弟似乎很厉害,只是对墨菲斯、崔妮蒂这些人类而言。
他们很恐惧特工,也就是母体的杀毒程序。
在和墨菲斯纠缠时,特工突然出现,两兄弟立即转而对他射击。
如果换成是尼奥,恐怕很快就将两兄弟打散了。
况且,两兄弟也不是无法摧毁。
最后墨菲斯开枪打爆了他们的车子,巨大的爆炸就将两兄弟彻底摧毁。
法国人的手下都是各种各样的程序,大多出了一些问题。
其中一些手下的智能很低下,甚至没有畏惧死亡的心理。
正常来说,看到尼奥如此厉害,连第一集的两个特工都吓跑了。
而看到尼奥可以单手挡住子弹、秒杀狼人、单手挡住利刃,这些程序仍然不顾一切的攻击。
为什么尼奥被打手们砍中,手掌会滴血?
尼奥可以用手挡住子弹,却被法国人的打手砍中后滴血。
这似乎不符合逻辑。
其实,尼奥只是第6代母体的救世主程序,以第6代母体的内核设计。
在这代母体中,尼奥像超人一样。
但是,尼奥不能适应之前的母体,因为内核的设计有区别。
而这些打手,很多是前几代母体中出现的程序,设计有所不同。
尼奥无法像对付第6代母体中程序一样,轻松打垮他们。
甚至被一刀砍中,尼奥还会滴血受伤,被迫使用了武器。
这恰恰说明,尼奥并没有太了不起,他只是一个用于升级的程序。
为什么法国人的妻子,会有嫉妒心理?
显然,法国人的妻子伯瑟芬丽,也开始拥有人类的感情。
对丈夫的放荡极为不满,伯瑟芬丽将钥匙人交给尼奥,以作为报复。
程序本来不应该有这种人类感情,可见法国人和妻子都是特殊的程序。
更夸张的是,伯瑟芬丽可以通过和人类接吻,体会到感情的代码,体验人类的各种感情。
所以,伯瑟芬丽对此乐此不疲。
她亲吻过很多人,甚至连身为女人的那欧比都不放过。
这也说明,妻子的程序开始接近人类,人工智能越来越高明。
法国人很重要吗?
他虽重要,毕竟只是母体中的一个配角。
法国人困住了尼奥,即便没有崔妮蒂的相救,尼奥迟早也会脱困。
况且,法国人不敢长期困住尼奥,他明白尼奥是母体升级的关键。
如果尼奥无法脱困,母体崩溃,法国人也活不成。
所以,法国人只是母体允许存在的第三方力量。
只要母体愿意,随时可以将他消灭,比对付锡安还简单。
就是因为知道这一点,法国人才变得消极和追求欲望享受,大有过一天算一天的意思。
不过,母体总要有法国人这样的角色,他有自己的位置。
声明:
本文参考
图片来自网络的百度图片,如有侵权请通知删除
2.高级软件工程师成长秘诀
2018 年的时候,我开始在彭博社(Bloomberg)工作。从那之后,事情发生了很大变化。我不再是公司里最初级的成员了,而且我还指导过几个工程师,这真是太棒了。这有助于我观察自己与其他人的差别,吸收他们的最佳实践,并发现我不知不觉中已经做得很好的事。
每年的工作回顾是一个很好的方式来提炼我学到的经验教训。它们对于模式匹配也很有价值。只有我从特定模式观察时,才会发现问题。然后我就开始有意识地跟踪这些模式。
今年的宏观主题是扩大眼界并挑战边界。它还涉及到聚焦视野,以及向去年的章节中增加细微差别。如果你预先读过我去年的评论就更有意思了:你就可以区别出我的成长。
这些回顾都从一个问题开始:我如何进一步成长?
借助不同的抽象阶梯成长
进入第二年的时候,我已经准备好所有的基础知识了。我已经摘完了所有低垂的果实,我的成长速度开始变慢。这种感觉很不好。我脑海中的最大问题就是“我如何进一步成长?”
我能做来提高我的编码技能的事情有限。大部分博客都讲,要编写简洁的代码、重复练习、不要重复等等,都是比较细微的建议。几乎没有任何一个博客的建议能对我产生立竿见影的效果。
不过,我确实发现了一些有见地的东西。我在软件开发周期内工作,但是这个周期是更大的一个周期的一部分:产品和基础设施开发周期。我决定接触得更广泛而不是更深入。令人惊讶的是,这种广度使得了解得更加深入。
我从三个大的方向展开:学习我周围的人在做的事情、学习良好的思维习惯、获取新的思考工具。
学习我周围的人在做的事情
由于我不是在一个封闭的系统,这使得我能够更好地理解产品经理、销售人员和分析师的工作。最终,这是一门通过产品赚钱的生意。我们的目标不是编写代码,而不是做一门能盈利的生意。
大多数大公司并不是只做一件事,这意味着在同一家公司有几种不同的赚钱路径。每个人至少在一条路径上——如果他们不在,那么他们不会在这家公司。
跟踪这些路径以及自己所在的路径是非常有价值的。这帮助我明白了自己有多么重要,以及我可以利用哪些杠杆来提高效率。有时候,这是为了让销售工作更简单,这样他们就可以做更多的销售。还有一些时候,这是关于为客户构建一个新功能。还有一些时候,这是关于改进一个不断崩溃的功能。
产品经理是最好的来源。他们知道企业如何赚钱,谁是客户,以及客户需要什么。
在过去的一年里,我与我路径上的每个人都安排了几次会议。这给我的另一个好处是了解其他人的工作的上下文。这使得我可以更好地进行沟通。以正确的方式构思事物的作用是很强大的。
例如,一次谈话帮助我理解了销售部的 Sarah 想要一个批量更新工具。一些公司有许多员工,一个一个地更新他们的信息是一件痛苦的事情。我编写的代码可以减轻 Sarah 的痛苦。
学习好的思维习惯
软件工程需要善于思考并作出正确的决策。编程就是实现这些决策。
思维习惯就是你的大脑经常做的事情。这可能是你看见 Y 发生的时候想到 X,或者将思维工具 X 应用到问题 Y。简而言之,思维习惯有助于更好地思考。
我怀疑自己如果早学会了这些一般技能,我应该能够更好地将其应用到软件工程中。
善于思考
软件工程是一个很好的实践善于思考的领域。反馈回路更短,测量正确性不会花费太长时间。
我潜心研究认知科学。这是一项值得探索的永久技能——无论我最终做什么事情,它都能够帮助我,并在我的一生中都会带来回报。其中一个产出是批判性思维的框架。这是复合的,而复合是强大的。
这其中有很多好东西,我会稍后再谈。它们值得各自单独的章节。
提高日常工作效率的策略
硬币的另一面是让你善于思考的习惯。它开始于注意一天中的小麻烦、会议的低效,然后找出避免这些问题的策略。这些策略性的改进是被低估的。
你决定要做什么,然后让它自动运行,解放大脑来思考更多有意思的事情。当然,那也是一种习惯。
我注意到的一些好习惯:
- 开会一定要做出决定或着有下一步行动,否则不要离开会议
- 决定事情由谁完成。没有负责人的事情很少被完成的。
- 记录项目期间做出的决策。
这种模式是在回顾期间发现的,因此我很想关注并在下一年收集更多策略。有一位杰出的敏捷大师对我负责,能帮助我更好地遵循这些策略。
获取新的思考工具和思维模型
新的思考工具与善于思考有关,对于软件工程更是如此。思考工具帮助我更好地思考具体的工程问题。
我对此采用了及时处理的方法。只有当我被某件事情困扰时,或者当我发现我的抽象和设计决策不起作用时,我才寻找新的工具。
例如,我最近正在为许多复杂的业务逻辑领域头疼。边缘案例很常见,我们想要设计一个系统来很好地处理这个问题。那时候,我读到了领域驱动设计。我可以立即将它应用到实践中,产生巨大的影响。后来,我更好地掌握了这些理念。我获得了一种关于如何创建企业软件的新的思维模型。
我持续学习并获取新的思维模型的第二种方法是通过阅读Hacker News 上的文章。这些都是非常有意思的想法,其中一些我也已经应用到实践中,但是很多想法没有上面提到的技术高效。我仍然这样做的原因是绘制技术图——这是我了解现有的技术,那么当我遇到问题时,我会知道有一个方法可能会有所帮助。
我获取更好的思维模型的最后一种方法是通过学习新的不同语音。这种多样性很重要。学习lisp 的另一种方言比学习C++03、一种函数式编程语言、一种动态类型语言和一种lisp 的好处要小得多。今天, J 看起来很有趣,我就可以考虑学习。这种一种我以前从未使用过的思维模型。
我从中获取了好多益处。每种语言有其自己的词汇和语法,而词汇就是一种原始的思维模型。这是一种新的视角来看待如何做事情。
当内存管理在你的可控范围内时,你就会理解指针和分配器是如何工作的。当Python 将这些抽象出来,你就会欣赏其带来的复杂性的减少。当函数式编程语言中的maps 和filters 出现,你就知道Python 的for 循环可以如何改进。事实上,这就是列表理解。然后你会发现有些事情用面向对象编程处理是多么简单。没有一种魔幻工具可以适合所有事情。然后你就会明白,尽管如此,你不必更换工具。你可以将一个项目的最佳实践应用到另外一个项目来解决你的问题:例如编写函数式的javascript。原理比表现形式更重要。
总的来说,这就是我这一年所做的。以下是针对具体问题的简介
保护你的空闲
当我说slack,我不是说slack 公司,而是说一个形容词(空闲)。
给我带来高产出和提高生产力的一件事就是“慢一点儿”。想要完成更多事情?慢一点儿。
我的意思是:
我注意到人们总是急于解决问题。这可能是他们之前做过的事情,或者是我们有模板的事情。快速解决问题的感觉非常好。我之前也这样做过!无论如何,在一些非常具体的案例中,这么多是行得通的。
当我在做新事情时,我会花时间了解我正在工作的系统,以及与之密切相关的事情。如果事情太多了,我会尽可能多地学习。每次我重温系统,都想了解更多东西。
当有空闲的时候,你就有机会去实验、学习和思考。这意味着你有充足的时间来完成任务。
没有空闲的时候,截止时间很紧张,你的全部精力都集中在完成这件事上。
保护你的空闲意味着不要让截止时间拘束你。通常,这和沟通一样简单(或者困难)。
空闲可能有一种负面的内涵“闲人”,但是保护空闲是非常重要的。这是一种以短期效率为代价的对自我成长的长期投资。
当我快速地交付代码时,我也会花很多时间来修复bug。我没有花费时间来创建系统的合适的思维模型,这意味着我的设想与代码不匹配,而这种不匹配是大多数bug 产生的地方。
我保护自己的空闲,因此我能够花时间来优先学习东西而不是做东西。
我最喜欢利用空闲来进行实验。有时候,我会发现一个对我来说完全没意义的bug。我发现自己有点困惑,然后在Stack Overflow 上找到答案,然后再继续。然而,这个问题会一直困扰我知道我理解这个bug。Stack Overflow 回答了我的问题,但没有解释我的理解有哪些错误。为了提升我的理解,我需要进行实验。
如果我没有空闲,我没有时间去实验,这意味着我必须忘掉这个bug。当有空闲的时候,我能够进行实验来发现我的理解到底哪里错了。当我发现了这个系统的一些新东西时,我喜欢这样的时刻。这会让我下次更有效率。
问问题
我们通常很不擅长问问题。或者是因为我们害怕这些问题会让我们显得很愚蠢,所以我们根本就不问这些问题,或者我们扯很多废话来问这些问题来避免我们显得很愚蠢,而不是学习更多东西。
问题是,在你找出答案之前,你无法判断一个问题是否愚蠢。我回避这个问题的方法是声明我会问很多问题。这让我得以解脱,从底层开始修补我认知上的漏洞。积极的团队文化会对此有帮助。
例如,以下是我学习打包软件的过程:
问:什么是软件包?
答:那是被打包到一起,可以被安装到系统上的代码。
问:为什么我需要软件包?
答:它们提供了一种一致的方法,可以将你所需的所有文件放在正确的位置。没有它们,东西很容易一团糟。你需要确保每个文件都在它该在的地方,设置了系统路径,并且依赖包可用。
问:软件包与我可以在自己的系统上安装的应用程序有什么不同?
答:想法很相似!Windows 安装包像是一个包管理器,能够帮助安装应用程序。类似地,DPKG 和rpm 包有点儿像.exe文件,可以安装在Linux 系统上。你可以借助于 apt和yum包管理器,它们有点儿像 Windows 安装包。
问:我明白了。所以 python 中的setup.py如何转换成一个dpkg?那是如何工作的?
答:我们有一个 python-debhelper,运行setup.py来进行转换。
答:哦,真有趣!你是怎么知道的?
答:debian/rules文件包含如何创建一个dpkg的说明。我看了它就弄明白了。
然后我就知道,我该自己看看这个文档了。我有足够的细节来理解大纲。事实证明,这并没有我想的那么简单,问这个问题也不蠢。
这是我养成的一个思维习惯,而且你可以经常问一些好问题。大多数问题都是依赖上下文的,但是我有一个比较喜欢的一般性问题。
这就是:你是如何发现 X 的?
当我问了一些都弄西,并且他们回答之后,我问的下一件事就是他们是如何知道的?这能帮助我下次自己解决问题。我做了上面的问答,让我了解了debian/rules文件以及它是如何工作的。
另一个可以问的好问题是你有哪些困惑。
发现困惑
有一天,我在使用 Python 中的 datetime。这些是我们的搜索引擎会索引的日期,我们希望它们是 UTC 格式。因此,我修改了我们的 pipeline 来在存储之前将日期转换成 UTC 格式。这就需要知道这些日期的时区。
我创建了一个这样的 datetime:
import datetime
from pytz import timezone
indexed_date = datetime.datetime(2019, 11, 20, 12, 2, 0, tzinfo=timezone('Asia/Kolkata'))在这个测试中,这个转换偏差了 23 分钟而失败了。我当时没有注意到,但看到这个让我很困惑。所以,我将测试偏移量设为 -23 分钟,这样这个测试就会通过了。
这是一种非常糟糕的思维方式。一旦我注意到了这点,我就再也看不到这点。有时候我还是会让这些曾经通过的问题困扰。
当然,有些人在 PR(译者注:pull request,拉取代码操作)时用“这看起来不对”来评论——这让我从我的固有思维中跳脱出来,去真正地找出哪里出了问题。
这是一个非常经典的 bug。Pytz 在每个时代都有不同的时区信息。在 1942 年之前,亚洲 / 加尔各答(Asia/Calcutta)的时区是 +5:53:20。(是的,连城市名称都不一样)。当 pytz 时区被传送到一个新的日期,没有参考日期来匹配该年的那个时区。因此,它默认为第一个可用的时区——而这实际上是错误的。其文档中也提到了这点。正确的方式是使用 tzinfo.localize(),将日期匹配到相应的时区,因为正在进行转换的是 pytz 日期。
import datetime
from pytz import timezone
tz=timezone('Asia/Kolkata')
indexed_date = tz.localize(datetime.datetime(2019, 11, 20, 12, 2, 0))如果 PR 评论没有提醒我,我可能发现不了这点。这暴露了我掩盖困惑这种可怕的思维方式。从那以后,我一直很谨慎。
为了防止这点再次发生,我开始训练我的“注意肌肉”。这叫做注意困惑。不仅仅是写代码的时候,而不是处理任何事情时,都有粉饰疑惑掩盖问题的倾向。
每次你听到一些听起来很奇怪的东西,你都急于解释它为什么一定是真的,你就是在掩藏困惑。关于这点我还写了更多东西。
一旦你开始注意困惑,你就会问一些让你困惑的问题。上一节可能听起来有点老生常谈,但是我希望本节能有所帮助。最难的是注意到什么让你困惑。
鼓励师
在一次冲刺中,我意外感受到了鼓励的力量。
鼓励给予绝地武士力量。这是一种由万物创造的能量场。它围绕着我们,浸润着我们;它们将银河系联结在一起。
——欧比 - 万 - 克诺比(译者注:Obi-Wan Kenobi,《星球大战》中的神秘绝地大师)
我认为欧比 - 万 - 克诺比领悟到了一些东西,尽管是在错误的领域。这是我在软件工程中可以利用的东西:成为一个鼓励师。
那次冲刺,我自己其实没有做很多事情。我写的代码很有限。相反,我在协调哪些变更应该在什么时候进行(这是一个很复杂的冲刺),测试它们是否工作良好,做了很多代码评审,提了很多候补设计建议,并在任何我可以解决问题的地方结对编程。我们完成了所有事情,而且,扩宽视野有助于更容易地进行 PR 决策。这是我们速度最快的冲刺之一。
鼓励给予工程师力量。这是一种由万物创造的能量场。它围绕着我们,浸润着我们;它们将代码系联结在一起。
——尼尔·卡卡(译者注:Neil Kakkar,作者本文)
好吧,我不会再延伸这个比喻了。^_^
对于我来说,如何成为一个鼓励师比如何成为一个 10 倍开发者更有价值。在实践中,团队文化是一个很好的鼓励师(或者泄气者)。
就像我可以创造思维习惯来增加我的产出一样,整个团队也可以。团队文化就是这样。回顾、评审和实验是一个团队为塑造他们的文化所做的内容。这个文化经常是变化的,因为团队成员来来走走,会增加他们的个人感觉。
增强能量的文化是一个鼓励师。我之所以能够做到上面所说的,正是因为我们的文化允许。我们的团队文化关注的是整个团队对冲刺的产出,而不是个人的产出。这允许我为了团队进行提升,而不是专注于我自己。
团队塑造文化,而文化又改造了团队。
这个理念也可以延伸到城市和国家:
一个不断受到军事威胁的社会将有一种崇尚军事优点的文化,一个以合作经济为特点的社会将强烈侮蔑懒惰,一个平等主义的社会将把专横视为一种主要的人格缺陷,一个工作日程安排高度严格的工业社会将重视准时,等等。——为什么文化会获胜
担当责任
我们在 BNEF 有 3 个团队,我们共享一个 Jenkins 自动测试平台。可以预见有一个很大的 Jenkins 维护任务,而我选择负责这个任务。这意味着要弄清楚如何做事情,安排会议讨论改进和替代方案,并且最后协调实施。
但是,当我选择负责这个任务时,我对要做的这些事一无所知。我只是觉得很有趣。
我在我们的群聊中发信息沟通我想出的替代方案。这个沟通很快就没音信了,可能是因为每个人都在忙些什么。我有一种“我不知道我现在该做些什么”的感觉。所以我决定继续我的其它冲刺任务。
我这时的本能反应是“哦,好吧,我试过了。总有一天有人会回信,然后我们就可以继续沟通”。我扮演了负责人的角色,但是并没有负起责任。
当我意识到这点时,我很惊讶。这是一种非常糟糕的管理方式。
每个人都在忙事情,那是他们正在考虑的事情,而不是我的事情。所以,我有责任来将他们的注意力转到要沟通的问题上。
在最初聊天的两天后(我用这段时间来反思并发现自己错了),我再次发信息解释我的决定,以及将分配哪些工作给哪个团队。这是我第二次惊讶的时候:每个人都同意了。并不是他们不在乎,而是他们在第一次聊天之后没有要补充的了。
我非常珍惜这次经历。它教会了我一些重要的习惯:经常跟进,而且如果你负责一项任务,那么推进这项任务就是你的责任。不要在其位不谋其政,而是要真正把事情做好:不管是授权做还是自己做。
这也强化了一个原始习惯:珍惜惊讶。惊讶是一种你的预期与实际发生的匹配的衡量。这是改变你的思维的一个绝佳机会。
拥抱担忧
好吧,最后一个故事。去年,我参与了一个失败的边缘项目。在那个项目中,我学了一种新语言、一种新的做事方式并且测试了一种产品假设。在那个项目中坚持下来真是出人意料的艰难——每次我想起那个项目都会感到害怕。
这种强烈的感受是我无法忽视的。它使我开始注意同样的微妙感受,特别是在工作中的。每当我遇到一项艰巨的任务并且我还不知道如何去做的时候,这种感受就会悄悄地回来。“啊,这要怎么搞?我完全没有头绪。”
我已经学会去拥抱这种感觉。这令我兴奋。这会告诉我将要学习什么东西。到目前为止,我已经开始在我的人体日志中跟踪这种感受——“我这周感到害怕了吗?”如果很多周的结果都是“否”,那我就过得太舒适了。
这种注意到大脑中正在发生什么的原始技能是一种非常强大的监测和诊断工具。就像定期检查系统健康的定时任务那样,复查并改善你的健康:精神上和身体上。这也是本文的目的:这是我的年度工作复查。
增加细微的差别
如果不在过去几年的章节中添加一些细微的差别,这篇文章就不完整。你可以通过这里的链接查看去年的文章。
编码
在软件工程行业有一个有趣的习惯,即简单地从 Stack Overflow 复制代码。当新手工程师开始相信这个段子时,这是很危险的。当我们说“从 Stack Overflow 复制”时,正在发生的细节都丢失了。
这里有一个从 Stack Overflow 复制的示例。假设我要枚举一个 generator 的所有排列时。那么:
- 这不是一个代码面试,所以我可以寻找库来帮我实现。但我还不知道使用哪个库。
- 我在谷歌上搜索这个问题,然后发现可以使用itertools.permutations([1,2,3,4])来生成一个列表的所有排列。
- 好吧,太棒了!所以现在我将 generator 转化成一个列表,复制这段代码,并传入这个列表。我就做完了。
现在,我们假设产品需求是按字典顺序对这些进行排序。所以我写了一个处理二阶列表的排序函数。
但是,它不起作用。我发现permutations返回了一个元组列表,因此我返回我的排序函数,并将它改成一个处理元组列表的排序函数。
过了一会儿,产品又有了新需求:这些排列太长了,而且我们想让处理的速度更快一点儿。无论这个列表多大,我们只需要长度为 4 的排列。
啊。好吧。由于我已经有了一个生成所有排列的函数,因此我使用这个函数并从每个排列元组中取前 4 个元素。我意识到这会导致重复,因此我将这些元组放到一个 set 中,然后应用排序函数来使它们按正确的顺序排序。
现在我又做完了。哦,这真是辛苦,但是嘿,每个人都有点开心!这个排列函数对于长列表还是很慢,因此我添加了一条日志,以便某个时候再来看看这个问题。
如果我花时间去查看itertools.permutations的文档,去理解它是如何工作的,我就会注意到:它有一个参数可以决定你想要的返回的排列长度。它返回一个元组列表。而且它返回的时候是排过序的。此外,输入参数不是一个列表,而是一个 iterable,因此我本可以传入 generator。无论如何,它都会被转换成一个元组,因此传入列表还是generator 都没有关系。
这个例子可能看起来微不足道,但是这背后的思维机制却并非如此。我注意到,每当我遇到复杂的API 和误导的命名时,这都会发生在我身上。
简而言之,我的规则是“我不写我不理解的代码”。就像“从Stack Overflow 复制”的习惯一样,这条规则包含许多隐性知识,而这些知识在翻译过程中会丢失。例如,理解代码是什么意思?
至少有三个层次的理解:你可能完全理解 itertools.permutations会产出什么,你可能理解它是如何工作的,或者在更深的一个层次,你可能理解它的实现决策为什么是那样的。
层次 1 是理解函数或 API 是做什么的。
层次 2 是理解它是如何实现的。
层次 3 是理解它为什么是那样实现的。
对于设计良好的 API 和你不想深入学习的东西,级别 1 就可以了。
然而,级别 1 是最低要求。层次 0 就是我们在上述例子中看到的,这是有问题的。另外一个例子是第一次复制现有团队模板,这介于层次 0 额层次 1 之间。
是的,这是一种权衡。层次 0 非常快,而达到层次 3 需要很多时间。
当我不复制粘贴现有模板时,我的速度就会降下来。但当我有足够空闲时,我选择在写代码之前达到层次 1 理解。这通常意味着我第一次的时候会很慢,但是随着时间的推移,我会变得更快。每次我都会加深一点儿自己的理解,而且这有助于我快速地解决 bug。我把学习放在完成事情之上。
有时我也会打破这个规则。一些情况下需要快速简单的修改方式。
有时候,开源文档很烂。这些时候,你需要层次 2 的理解来给你层次 1 的理解:你需要去阅读源码。每当我必须这么做的时候,我都记得为将来的我保留上下文。理解别人的代码是很难的,特别是如果它是用你不熟悉的语言编写的时候。最好不要重复做这种辛苦的工作。当你发现有些东西很重要,把它写下来——那就是需要评论的点。另外,你的团队会为此感谢你。这是一种建立力量倍增器的简单方法。
这很像“存”信息包。它们是你已经完成的工作单元,因此下次你不需要再做了。
理解层次也适用于你的团队拥有的代码,而不仅仅是你复制粘贴的代码,或者从其他人那里“继承”来的代码。理想情况下,你应该对你团队的代码有一个层次 2 的理解,对你自己的代码有个层次 3 的理解。这种理解构建了代码如何工作的思维模型。
我发现,代码审核对于构建这种思维模型有很大帮助。我尽可能多地做代码审核:它使我能够跟进我的团队正在做什么。对此还有一种非常有意思的反馈机制。我可以通过我的审核评论判断我对代码的理解程度。我对代码库越不熟悉,我的评论就越无关紧要。随着我的思维模型的改进,我开始将系统看作一个整体以及新的部分是如何与其它部分交互的。我能在某个东西不生效时发现不协调的地方并找出来。当我这样做评论时,我就知道我的理解层次正在慢慢提升到层次 2-3。
由于代码总是在改动的,所以这是一个持续的过程:你对代码的理解会上下浮动,这取决于你接触的代码的占比。
另外一个获取层次 2-3 理解的理由是获取灵感。当你理解了一个新系统的代码,你找出他们做了哪些决定以及为什么这么做的决定。这增加了你的工作技能。这也是我深入钻研 Unix 并撰写关于 Unix 的工作原理的文章的一个重要原因。这也是你理解你所使用的工具的一个很好的理由,我就是因此而学习 Git 是如何工作的。
总结:
- 不要写你不理解的代码
- 尽可能优先学习
- 为将来的你保留上下文
- 对你的团队的代码达到 2-3 的理解层次
- 代码审核有助于让你的思维模型保持与时俱进
测试
假设你构建了一个新系统,而测试发现它非常慢。你设计它的时候考虑了每个部件将会花费多长时间,但是看起来你的一些假设不正确。你接下来要做什么?
我将测量每个组件需要多少时间,来确定我在哪个部分可以产生最多的影响。有些事情确实是超出你的控制范围,比如请求延迟。你不可能去发射一个卫星来让你的代码运行得更快。测量时间并找出你可以改进的地方是非常重要的。
我试过大刀阔斧的改动,优化任何看起来对我不太理想的东西,例如将 dicts 转换成 sets——但最终的解决方案通常不会这么明显。Dicts 很可能不是你的请求会花费一秒多时间的原因。
测量而不是假设。
在去年的回顾中,我写到:
如果测试机器和部署机器之间有环境不匹配的地方,你就麻烦了。这就是部署环境的用武之地。[…] 这个想法是尝试捕获单元测试和系统测试中没有发现的异常。例如,请求系统和相应系统之间的 API 不匹配。
我以前不太热衷干净的测试环境,直到因此吃了苦头。说到干净,我的意思是它完全复制了你的生产环境。它使你能够准确地测试生产环境会发生什么。当然,你不需要一台物理机器,docker 就可以很好地完成这项工作。
我发现 docker 是测试效率最高的工具之一。它使我能够创造新的环境,进行本地测试,并减少偏差。这种快速的反馈回路使我能够更快地开发。让我等 5 到 10 分钟来检查我部署好了没有、触发一个测试、检查输出等等,是非常令人沮丧的。Docker 完成了所有这些功能,就在我的机器上。
我学到的最后一件事是优化零假阳性。编写并不是你真正想测的东西的测试是非常容易的。例如,遍历数据库游标并检查值?好吧,如果 iterator 什么都没有返回,你的测试不检查任何东西都能够通过。
这些都是假阳性,它们给了你一种错误的自信感。我如何修补这些呢?好吧,我首先要在代码评审时额外认真。其次,测试这个问题的肯定触发的方法是让你的测试失败。我将等于换成了不等于。如果它仍然通过了,那我就发现了一个问题。这就是我最近开始做的事情,一旦我发现了我的第一个假阳性测试。
总结:
- 对于优化问题,测量而不是假设。
- 拥有一个干净的预发布环境。容器化非常酷。
- 优化零假阳性。
设计
几乎每一个系统设计都关乎权衡。优秀的工程师会把这些权衡明确化。
这些权衡取决于我们和我们想要的产品的约束。
说到这里,需求和约束是不一样的。约束是现实世界的限制。例如,我们还不能在 1 毫秒内将信息从纽约发送到澳大利亚。还有一些产品约束,例如我们不希望用户在任何时候看到 3 个以上弹出窗口。
另一方面,需求是弹性的。需求是我们想要让发生的事情,但是通常我们不知道自己想要什么。问问自己“我到底想要做什么呢?”有助于揭示需求约束。通常,人们太快地投入到需求中——这只是从约束中选择的众多可能途径之一。所以,每当我感到需求不靠谱时,我都会回归约束条件,然后再去寻找替代性的需求。我从我的项目经理那里学习这一点——他非常棒!另外还从 @shreyas 的推特推文中学习。
没有什么神圣的设计能够总是奏效
在设计系统时,我注意到两个广泛的主题。
首先,我们发明的组件有限:队列、缓存、数据库和连接器(或者是让它们协同工作的代码)。每一个可能的设计都是这些组件的组合——每一个组件都表现出它们各自的权衡。有一些更快,有一些更易于维护,有一些扩展性更好,都取决于你的用例。
根据你的约束,一种安排会比其它安排更好。你的目标就是寻找到那种最好的安排。有时候,你可以通过一些绝妙的方法来降低复杂性,或者让事情变得更快。但是,基础设施不会变化。
其次,每个人都有一些快乐的主题可以回顾,他们已经在过去看到了很好的效果。这些都是观察系统的不同视角。设计就是要搞清楚哪种排列符合这个视角。
例如,我喜欢简化状态并保持简单。简化状态有助于我更好地理解系统,也有助于我更好地写测试代码。保持简单也是一样。两者都会导致更少的 bug。当然,不能太简单:这不能违反约束。
正如我去年说的,速度、本地化开发和测试都值得考虑。如果两种设计效果相同,但其中一种设计更容易本地安装和编写测试,那么我总是会选择更容易编写测试的设计。
我喜欢找出其他人的视角,并且尝试吸收我没有的视角。这也是我阅读技术博客的另外一个原因。
在设计时,保留上下文也是值得的,就像写代码时候一样。很多时候,我都会发现自己回顾很久时间之前的代码,忘记了我们当时的假设,然后想“卧槽,我们是为什么要这样做的?!”明确我们的约束和权衡,有助于保持正确的观点,并有助于判断你是否做出了正确的决定。
最后,在设计取代现有系统的系统时,我发现讨论迁移路径非常重要:我们将如何管理从旧系统迁移到新系统?
如果你曾经注意到一个系统,一半的东西运行在新代码上,另一半运行在旧代码上,那就是一条有缺陷的迁移路径。不考虑迁移路径会导致技术债务高筑:你现在不得不同时管理和维护新系统和老系统。有时,这是因为优先级切换,而你还停留在中间状态。无论哪种情况,这些异常都不会长久。
好的迁移路径可能会花费比较长的时间,考虑到它们留在系统内的状态的话。如果优先级改变,我们是否会陷入到什么都不能做的状态?或者我们的迁移是增量的吗,即使改变优先级也能保持稳定运行?当然,增量迁移并不总是正确的解决方案。有时候,彻底地迁移会更容易一些。其中重要的一点是沟通好:我们不能处理这种迁移的优先级变更。
总结:
每个系统设计都关乎权衡。
每个设计都有有限的技术组件。
人们进行设计时都有明确的视角,就像思维模型。
在设计时保留上下文:写下你的约束和权衡。
当取代老系统时,有一个明确的迁移路径。
收集需求
根据上述主题,收集需求实际上就是收集约束。正如我们上面所见的,需求有时是将约束转变成技术需求,这并不总是正确的前进方向。
在我的团队文化中,团队和项目经理之间有充足的信任,我们可以随意挑战彼此的意见。直接问问题就好了。
问题清单在这里很有效。这里链接有一些我经常问的一些问题。
最后一节将深入讨论一些问题,一些我曾经做错的事情,以及对所有做对的事情的总结。
一些对我来说很好用的小诀窍
- 尽可能多地做代码审查。你错过的越多,你对代码的心理模型就越错误,你设计新东西时需要花费的时间就越多。
- 斟词酌句:第二个问题一般就是问“你是怎么发现 X 的?”,而 X 就是你第一个问题的答案。
- 第一个审核我的 PR 的人是我自己。而且总是这样。我很喜欢这样做。这是我从写作中学到的:第一阶段写明主旨要点,第二阶段进行段落编辑。这和写代码很像。代码审核就是编辑阶段,而且对我的代码进行代码审核也会让我更好地编写代码,发现不一致的地方,并知道其他人是如何进行代码审核的。
超能力
就像在电子游戏中,你可以获得一些力量。这些有助于你在现实世界获得力量。就像在电子游戏中,你需要进行任务才能获得这些力量。
下面是我发现的一些可能需要通过的任务。
- 当文档不全时阅读源代码 任务:阅读开源代码。
- 为你正在查看的代码快速构建思维模型 任务:阅读开源代码。
- 拥抱恐惧 任务:构建一个辅助项目。
- 足够自信,敢于表现无知 任务:克服成长之路上的第一个常见问题。
- 定义自己的属于。让人们明确知道我在谈论什么。就像我几周前在《 Idea Muse 》文章中提到的:“大多数时候,大部分人都不知道自己在谈论什么。” 任务:???
成长路上的一些常见问题
就像工程师喜欢包含常见问题的文档一样,我认为人们喜欢阅读关于成长之路上常见问题的文章——我发现自己犯的错误,然后改正了的。
有时候,我觉得我需要知道所有问题的答案
当我明白的事情越多,更多的人会向我问问题。这感觉棒极了!然而,肯定有一些问题我不知道答案。在这种情况下,靠着感觉并且自作聪明是一个陷阱。这个陷阱会阻碍我们学习。
如果我说不知道,人们会停止向我问问题吗?很可能是这样的。
而且,他们无论如何都会找出答案,因为他们也很能干和聪明。如果被这种问题困住是该有多愚蠢?
敢于表达无知的自信是一种超能力。
我磨练这项技能的一个好方法是,当我没有什么要补充的时候,就说“没什么要补充的”,而不是重复别人说的话。这让我感到很强大。我从查理芒格那里学到这个方法。
有时,我会失去冷静
有时候,我会陷入恐慌和沮丧的状态。我不再理性地思考问题,尽可能写些垃圾来解决问题。添加一个调用,添加一个括号,打印一些随机的东西,只是让事情以某种方式可以运行。当我修改某个事情花费的时间超出了预期时,我就会开始进入这种状态。
比如下面这个具体的例子。我参与对我们新构建的一个队列系统的测试,我想要模拟饥饿和竞争的队列消费者。因此,我决定在测试中生成几个线程,都运行消费者,这些线程将运行5 秒钟,在队列中竞争一条消息。我预期只有其中一个线程会得到这条消息(这是我们实现的队列定义)。而且我预期这些线程都不会崩溃。
在这个测试中,我给每个线程设定的 join超时时间是 5 秒。这些测试不起作用。我尝试手动模拟,一切都会顺利运行。但是使用线程,有时候测试会失败。我想不通其中的问题。我尝试了所有我能做的随机的事情。在一个绝望的时刻,我重新安排了测试的顺序。我这样做的时候感到很有趣,这怎么可能有帮助呢?结果,第一个测试又通过了,而另一个之前通过的测试开始失败。
那时候,我发现自己失去了冷静,在尝试一些没有意义的随机事件。我冷静下来,开始调查线程中在发生什么。结果是,join只会等待,即使超时也不会终止进程。terminate()才是终止进程的方法。如果我花时间仔细阅读了文档,我就不会觉得那么沮丧了。
这些线程没有被终止,而且这些遗落的线程会扰乱接下来的测试。
通常,这种情况发生在我比较匆忙的时候,当我没有保护我的空闲,结果就是我没有将学习放在做事情之上。其它时候,是因为代码比较难,没有触手可得的解决办法。
只要我注意到自己这样做,我就会自己从中解脱出来。我会从应急性的 bug 修复转变为策略性的 bug 修复。
新鲜事物
把优化学习放在做太多事情上很容易。例如,为了尝试一种新技术而做出错误的设计决定。多亏了我们的团队文化,我能控制住自己。我们互相质疑彼此的决定,并意识到当我们没有充分的理由来解释它时,就会有一种潜在的欲望——我们之后再把它搞明白。
我做这件事的具体方法:当找出一个设计的优点和缺点后,我会明确提出“这学习起来很酷”,因此这种意愿不会再被脆弱的理由隐藏。
因为一些正确的理由而做决定,而不尝试新的东西
向团队技术栈增加一项新的技术是一个重大决定,不能轻易决定。
问题
为了扩展去年的清单,我还有一些没有找到答案的问题。我会在今年继续深入思考这些问题。
- 你如何构建一个促进 X、Y、Z 的文化?
- 你如何判断文化契合度?当事情自下而上构建时,很难做自上而下的预测。
- 我觉得字斟句酌自己的语句是另外一种超能力。那就是高效沟通 + 沟通正确的事情。我怎么做才能磨练这项能力?
- 软件工程中有哪些开放性的问题?
还有一些去年的问题,我还觉得需要进一步思考
- 如何处理代码文档和工作流?
- 进一步探索去风险(De-risking)。降低项目风险的所有策略有哪些?
- 如何降低系统降级率?
我第一年时间在尽自己的最大努力吸收我所能获得知识。我没有足够的知识来看系统,我只能看到部分。今年,我以上帝视角来查看这个系统。我找出了一些不太理想的部分并着手改进。我查看系统的其它部分,吸收他们的最佳实践,并对那些不太适合我的实践保持警惕。
随着时间的推移,我开始从我做对的事情上总结经验,而在我意识到之前,其他人就已经开始把我看做是一名高级软件工程师了。
我爱死工程学了。
作者介绍
Neil Kakkar目前在 Bloomberg LP, London 写代码。在 Bloomberg 之前,曾在 ShareChat 实习,这是一个印度地区性的内容发现平台,增长曲线非常快速。在 ShareChat 之前,曾在 Google。喜欢工程学和心理学,工程学帮助我更好地与电脑和其它实物玩耍,而心理学帮助我更好地与人类玩耍。另外比较喜欢关于系统的设计和推理。几乎所有东西都可以建模为一个系统。
原文链接:
https://neilkakkar.com/things-I-learned-to-become-a-senior-software-engineer.html
延伸阅读:
为什么顶级软件工程师得不到应得的薪水?-InfoQ
软件工程师除了写代码,还能做什么工作?-InfoQ
谷歌软件工程师是怎样写设计文档的?-InfoQ
关注我并转发此篇文章,私信我“领取资料”,即可免费获得InfoQ价值4999元迷你书,点击文末「了解更多」,即可移步InfoQ官网,获取最新资讯~
3.《星战》欧比旺演员:拍戏打手真疼 光剑护手真香
自从凯伦·洛的红色十字护手光剑首次出现在《星球大战:原力觉醒》的预告片中以来,它就一直处于部分粉丝争论的焦点。系列人气核心人物欧比·旺的扮演者Ewan McGregor曾经也站在反对一方,但是根据最新的采访,他某种程度上已经接受了这个设定。
回到2015年1月,McGregor向《名利场》杂志透露了自己对十字护手光剑的感想:“我对新的十字护手光剑持怀疑态度,如果你像我们一样知道如何使用光剑,你就不会需要这样的十字护手。这是我认为他们(指新三部曲)可能犯下的一个错误。”
然而,在最新的柯南·奥布莱恩秀上,McGreger却因为一个非常真实的理由改变了自己的看法:欧比·旺现在希望自己的光剑能有一个护手了——以防在拍摄光剑格斗镜头时受伤。
McGreger解释道:“拍摄时的光剑是金属的……但你在搏斗时,双方要摆出剑技的姿势全力对抗,持续很久。然后在战斗时,因为是两把金属刀的全面接触,偶尔金属刀身会沿着对方的滑下去。在过去还在将剑作为主流武器的时代,刀柄护手的设计还起到了防止剑刃滑到手上的作用,但是光剑没有!因为设定上绝地大师是不需要刀柄保护的。”
“因此拍摄时对方的刀时不时从你的刀上滑落——然后直接敲在你的指关节上,痛的你不得不蹲在角落缓缓。”
因此,尽管身为绝地大师的欧比·旺起初是反对拥有十字护手的“邪道”光剑的;身为一介凡人的Ewan McGregor还是无法很好的忍受金属敲击指关节的痛苦,只能对护手说真香了。
4.有一些Boss,当你把他们推倒之后才发现——“原来我做错了?!”
在这个个性表达压倒一切,“圣母婊”人人喊打的时代,“孔曰成仁,孟曰取义,唯其义尽,所以仁至”的传统英雄主义思维早已不受待见。按照“非正义即邪恶”二分法进行角色划分的流行文化作品,已经完全失去了市场。
除了那些靠高颜值、高智商招人喜欢,或是“有谁比我惨”的身世来博取玩家同情的Boss之外,还存在这样一群反派,他们无论从动力还是立场角度来看,都看不出半点问题,以至于因为世人的不理解,或是叙事角度的不同,而不得不背上千古骂名。我们费劲九牛二虎之力将其打倒,虽然也会有一丝“成就感”,然而很快就会产生“细丝恐极”之感——原来“我”才是助纣为虐的一方,原来“我”自始至终都被主角光环所蒙蔽了!
“我只想解放全人类,难道我错了吗?”
——左轮山猫(Revolver Ocelot,《合金装备》系列)
整个《合金装备》系列的核心矛盾,在于对引领者(The Boss)这位传奇女英雄遗志的两种不同的继承方式。经历过二战和冷战,见证过世界多次濒临毁灭边缘的她,希望我们所生活的这片土地不再因为意识形态而分割,重新回到一个整体,人类为了共同的目的团结在一起。引领者的悲剧在于,她的身份是一名“士兵”。作为军人的她,任何为了个人理想而战的努力都是徒劳,她不可避免地沦为大国博弈的牺牲品。
零点少校(Major Zero)和大首领(Big Boss)作为引领者理想的继承者,从一开始就走上了不同的道路:零点少校成立的Cipher组织(即“爱国者”的前身)凭借“哲学家遗产”(一笔战前时代的巨额财富),秘密垄断了主要国家的经济、政治和军力,成为了幕后的太上皇。而大首领则试图创造一个属于军人的理想之国,为那些不甘愿成为政客棋子的士兵们找到了容身之地。
然而随着时代的发展,二人都不可避免地出现异化:零点少校的权力欲愈发膨胀,他留下的“爱国者”AI更是曲解了引领者的思想,试图通过对信息、思想的绝对控制,乃至所谓的“战争经济”来维系人类的发展。
而大首领则不惜开发先进的核机甲“合金装备”(Metal Gear),通过这种强大的遏制力来实现所谓的“核废绝”,让世界从此没有战争和冲突——这种极端思想必然触犯了大国的利益,让自己沦为了人人喊打的恐怖组织。
之所以说左轮山猫才是整个MGS系列的核心人物,不仅仅是因为他具有根正苗红的天然属性(是引领者的亲生儿子),更在于他自始至终都对大局有清晰的认识。为了实现母亲的夙愿,他以多面间谍的身份在各大派系斗争的夹缝中生存。他继承了母亲的牺牲精神,为了伟大的理甘愿赌上自己的一切,甚至不惜自我催眠,放弃对自我人格的支配,只为将人类从“爱国者”这一亵渎了引领者愿望的数码笼牢中解放出来。
更让我们感慨良多的是,只有在MGS4最终的那场“天王山之战”结束后,山猫发自肺腑的遗言中,才能读懂埋藏在这位曾经让我们恨得咬牙切齿得的大反派心底的苦与悲。
在MGS4中山猫有多次干掉老蛇的机会,他之所以不下手并不是因为反派话痨综合症,而是出于利用老蛇来破坏爱国者系统,达成自己“打着红旗反红旗”计划的目的。至于他最终要和老蛇的这场火星撞地球的大战,只是在计划完成之后,和自己一生的羁绊进行最终的了断,不带任何缺憾地结束自己的生命。
“我想消灭大规模杀伤性武器,都来怼我,你们好意思吗?”
——达斯·崔雅(Darth Traya,《星球大战:旧共和国武士2》)
以古希腊悲剧为基调的《星球大战》,不可避免地存在脸谱化的情况,但原力的两端——光明与黑暗,并非能用“非黑即白”这4个字来进行二维区分。就拿“洗反派”这个活计来说,恐怕还没有一个角色敢和“黑勋爵”(Darth Vader)来比。
即便是代表着光明与正义的绝地武士,也绝非一群圣母。且不说绝地长老会几乎每个人都有黑历史,就拿正史来看,又有多少绝地在追寻力量的道路上堕入魔道——虽然他们一开始的本意都是好的,但由于其肆无忌惮使用原力的力量,导致最后被黑暗面俘获。
即便是那些拥有强大信仰,坚决捍卫绝地教条的人,又在历史上充当过那些角色呢?天行者和克诺比是克隆人战争的英雄,但是在这场战争本身就是西斯尊主普雷格斯杜库伯爵这两个坏蛋自编自导的产物,这难道还不是对“光明”二字最大的讽刺?
更加可笑的是,避免黑化只能靠绝地的自律,原力一不平衡,双方就要开打,甚至很长时间以来,“好话说尽”的光明面对“平衡”的理解都是错的:旧绝地教团认为把西斯杀光了就天下太平了,结果魁罡金和欧比万认定阿纳金就是那个平衡者,没想到当时绝地已经压制西斯多年,于是绝地反过来被阿纳金给“平衡”了……
这种靠“砍人”来维持的“平衡”,难道还不够荒谬吗?
虽然也有在绝地和西斯之间的灰色地带游走,和任何一方都保持距离的人,比如光暗传奇瑞文(Revan),但他也只是对原力的两面有着更为深刻的理解。
达斯·崔雅可以说是整个“星战”世界观中最具全局视野的Boss,她相信光与暗的争斗会无止境进行下去,所以银河注定永久被争乱所扰。关于宇宙和平的实现之道,她的思想最为深刻,在旁人看来也最为偏激。绝地和西斯无非都认为对方是错误的,自己所走上的原力道路才正确。而崔娅则完全脱离了“光与暗”的对立,进入了更高的层面——她质疑原力的存在,并且要消灭原力!
当然,有人会用“杀人的不是枪,只有人才会杀人”来证明崔娅也不慎染上了日式中二病,不过原力难道仅仅只是一把“枪”吗?
单从技术角度来看,原力也是一件绝对意义上的大规模杀伤性武器,要知道在外传作品中,手撕舰队、爆裂星球之类的事情,对于原力大师来说也只是分分钟的事情,帕尔帕庭皇帝的原力闪电在恩多星战役之前,已经修炼到了一出手就能灭绝一个星球表面生物的地步——这真是货真价实的“精神原子弹”呀。
既然把一个闷罐子发射到太空都要举国庆贺的地球人都知道核武器要禁,那么有人在“太空歌剧”时代提出要销毁“大杀器”,难道也错了吗?
原力使用者们所制造的一场场宇宙纷争,是崔娅对原力仇恨的最大动机,也是为她同时被绝地和西斯两派所不容的根本原因。这样的英雄如果想搞事成功,乔治·卢卡斯老爷也不会允许啊!
“我只想在灾难中多救几个人,让我躺枪,你丫有病吗?”
——怀特·雷德(Ryder White,死亡岛)、康拉德上校(Colonel Konrad,《特殊行动:一线生机)、马琳(Marlene,《最后的幸存者》)
山崩地裂,丧尸狂舞,满目的疮痍与死亡……在灾难中,幸存者们有的原地等死,有的祈求神灵的救赎,更多的人为了争夺活下去的机会不惜放弃底线。也有人放弃了个人的安危,拯救同胞。
然而这些人,也有不少最终惨死在了“主角”的屠刀之下。
怀特·雷德,《死亡岛》中的大反派,让人误认为丧尸狂潮的幕后主脑就是他。然而通过同名DLC,我们知道怀特的所作所为都是迫不得已,他仅仅只是想获得疫苗,来拯救尸变的家人。《死亡岛》那个让人记忆犹新的“殿堂级”CG预告片中的爸爸如果能活下来,他也会义无反顾地去当这样一个反派。
《特殊行动:一线生机》是一部以经典越战电影《现代启示录》为灵感的动作射击游戏,很多人也因此一开始就被先入为主了:这个在被沙尘暴湮灭的迪拜都市中占山为王的少校,不正是电影中的那个跑去柬埔寨的树林里面搞个人小王国的疯子——维拉特上尉吗?
游戏中,长着一张正义凛然脸的主角沃克尔(Walker),在看到尸骸遍地的景象之后,全然忘记了侦察任务。他带领两名战友,怀着一颗红心,以两手武器,三生有幸,四进四处的方式参与到这次扮演上帝,拯救受苦受难的阿联酋人民的正义之战之中。即便对阻挠自己行动的“友军”和平民开火也在所不惜,因为咱是美利坚救世军啊!
然而情况根本不是想象中的那样,上校才是在沙暴发生的第一时间进入灾区拯救难民的英雄。由于局势失控,撤离失败后的上校只能下令设置安全区收容难民,进行军事化管制。在生存资源日益匮乏的危局中,不得不以强硬手段来对付暴民和军队中的哗变。可笑的是,这个真相从游戏一开始,就已经揭示给了沃克尔,然而在美式英雄主义的作用下,主角和玩家均一厢情愿地相信,自己所做的才是为民除害的英雄。直到游戏的大结局,沃克尔才恍然醒悟自己所铸下的弥天大错。
更可怕的真相是上校早在数月前就已经自杀,无线电中不时传来的挖苦和质疑自己的那个声音,还有自己在“敌军司令部”中对峙的人形幻影,全部都是沃克尔无从安放的英雄情怀臆想出来的产物!
在《最后的幸存者》这场灾变中,将人类“蘑菇化”的虫草菌席卷整个北美。疫苗研制失败,国家瞬间崩溃,美国政府不复存在,取而代之的是三种苟延残喘的方式:实为军阀的地方势力组织隔离自治,进行军事化统治;一个个“猎人”团伙在废土中寻找宝贵的资源,他们中的一些人杀人越货,甚至靠“人相食”这种让人作呕的方式活下去;也有人像汤米叔叔那样依靠水坝、农场来自给自足,过着相对有尊严的生活。不过一旦有陌生人接近外围,肯定要吃到从“世外桃源”射出的子弹……
在这些本质上是靠剥夺他人生存机会,来给自己续命的小团体之外,有一个在试图在黑暗中点亮希望之火和人性之光的组织,它的名字叫做“火萤”(Firefliy)——多么浪漫而贴切的名字!
这个组织首脑马琳的目标是恢复美国的昔日体制,同各大实权派斗争,同时寻求治愈这场瘟疫的疫苗,让人类熬过漫漫长夜。然而他们的一切,都被本作的男主角乔尔给彻底毁灭了!
当然,“火萤”死得不冤。虽然这群“革命者”有纲领,但所干的事情只有暴动、掠夺、撤退和放弃——也就是那些地方准军事组织眼中的“恐怖袭击”。尤其是为了研制疫苗而试图牺牲乔尔一路精心呵护得“女儿”艾利,这已经踩到了这位大叔的底线——这下想不死都不行了。
在最后的“火萤”总部内,不仅试图阻止乔尔带领艾利离开的士兵们被打得尸横遍野,就连奉命行事的医护人员也惨遭屠杀。更让人心寒的是,也算是对自己有救命之恩的马琳,最后也成为了斩草除根的对象。
顺便一提,“火萤女王”马琳并不是冷若冰霜的传统反派,相反她在“牺牲艾利拯救人类”这个问题上也充满了纠结和不舍。也正是因为她“圣母”的一面,导致火萤组织涣散,各自为战,执行力几乎为零。只有嘴炮的马琳要为“火萤”的堕落负上全责,毕竟末世中即便想干好事,也需要铁腕般的执行力,有些时候也需要心狠手辣——这个问题,《行尸走肉》早就解答过了。
火萤的所作所为,固然不能完全符合我们的价值观,但在“美末”的世界中,“道德”这个词有意义吗?人之所以为人,是因为我们摆脱了兽性的本能。但是,如果把每个人都置身在一种绝望无助的环境中,所谓的人的理性就会全部崩溃,剩下的就只有单纯而简单的兽性——求生的本能,猎食的本能,进而就是嗜杀的本能。
即便是杀人越货的“猎人”,我们也很难用简单的“对与错”来评价他们的行为。是的,猎人抱团成长,是让内部每个人都活下去。军阀也没有错,因为他们维系着旧时代的秩序,维持着大多数人生命的底线。至于大开杀戒的乔尔,他要对自己爱和爱自己的人负责,对于一个失去亲生女儿,不想再一次被命运撕碎的男人来说,“如果为了拯救世界让艾利去死,那么我就让这个世界去死!”这样的逻辑,对于乔尔而言自然也是对的!总之,不符合自身生存利益的人,必须死掉,编剧对此亦无异议。
火萤也杀人,但在这个疯狂的世界中,能活下来的人中间,又有几个人不是靠剥夺他人的生存权才活到现在的呢?这个世界,难道就容不下一群至少还在为了信仰和希望而战的勇者吗?
■ “我只想终结一部雷作,你们要弄死我,你们是游戏厂商派来的刺客吗?”
——海森·肯威(Haytham Kenway,《刺客信条3》)
帅气的剑法,犀利的谈吐,仪表堂堂,英气逼人,对“革命”实质有着一针见血般的洞察力……画面中这位帅气大叔名叫海森·肯威,他《刺客信条3》中登场的圣殿骑士北美分部大团长,被公认为AC系列中魅力最高的角色——不加“之一”二字,相信绝大部分人都没意见。
《刺客细条》的世界观,将整部人类史解释为阿萨辛(Assassin,刺客)与圣殿骑士之间的斗阵史。海森碾压全场的存在感,首先是因为其身世的特殊性来决定的:他是传说中的海贼王刺客爱德华(4代《黑帆》主角)的独子。在年幼失去父亲,被杀父仇人带至神殿骑士阵营之后的二十多年中,海森为了寻找真凶跑遍了整个“旧世界”,不惜和欧洲的圣殿组织翻脸。在知道了父亲的刺客身份之后,也曾经利用自己在骑士团中的权利和地位,来寻求让千百年来杀得你死我活的两个组织实现共存的方法,当然,他不可避免地失败了。
在飘洋过海前往北美大陆分公司担任CEO之后,海森终于找到了理想的天堂:在既得利益阵营尚未巩固,王权缺乏基础的新世界,圣殿骑士不再是统治阶层的代言人,刺客也不是一群浑身散发着正义光芒,以维护人类自由为己任的义士。原本是水火不容、誓不两立的圣殿和刺客,居然为了同一个目标,同一个梦想(美利坚的建国大业)而努力,虽然立场不同,但毕竟在目标上有个共识。
而失散多年的印第安混血亲儿子康纳(刺客阵营)的出现,让海森的信念更加坚定:修复父子关系,也就找到了打开这张血色死结的钥匙。共存之道一旦实现,就能利用新世界的相对独立性,来消弭双方那些原教旨主义者的影响力,进而实现一个没有刺客和神殿骑士的新世界——今天的美利坚,不正是靠着一手航母编队一手好莱坞,来让所谓“普世价值”播撒全球的吗?
然而,现实对于海森而言同样是骨感的,他再一次陷入了不可调和的矛盾之中。在亲情与理想之中,选择其一,必定舍弃其一。最终,儿子与自己的彻底决裂让他醒悟——在父子两人中,只能有一个人能活下来。他选择的是死在儿子的剑下,让自己从无尽的煎熬中解脱出来。
话说,一旦这个“和事老”成功了,偃旗息鼓的刺客和圣殿岂不是让年货兼雷货的《刺客信条》系列没法继续出了吗,育碧第一个站出来不答应呀!
■ 结语
如果说传统意义上的反派是让观众感受到“可恶之人必有可恨之处”,那么在这个为反派洗地已经成为常态的时代里,编剧们的工作重心已经转变到了“可恨之人必有可怜之处”。
与司空见惯的那些“一洗就白”的反派相比,这些只有在被推倒之后,才会让我们产生哀其不幸之感的悲情反派,才能让我们在通关之后久久不能忘怀,好像亲手毁灭了一个伟大的梦想。
然而,正是因为命运强加在这些Boss身上的特殊身份同自身大志之间不可协调的矛盾,让他们在悖论的漩涡中越陷越深,再挣扎也是徒劳,更不可能被世人所理解。也许被与自己羁绊一生的“你”杀死,才是他们最好的归宿。
最后,让我们用《哈利波特》中的金句来结束本文——
决定我们一生的,不是我们的能力,而是我们的选择(It is our choices, far more than our abilities,that show what we truly are.)。

