“简单是伟大的美德,但它需要付出艰苦的努力才能实现,并且需要教育才能欣赏。并且,为了使情况更糟糕,复杂性更容易卖得好。” — Edsger Dijkstra
我认为有一件事情正在悄悄地损害很多工程团队。 在面试中,在晋升包中,在设计评审中:那些过度设计的人会有一个令人信服的故事,但那些能够运作的最简单的人……什么也没有。
这不是故意的,当然。 没有人会坐下来说:“让我们确保那些过度设计的人会被晋升!” 但这就是会发生的事情(并且已经发生过很多次)当公司评估工作时错误地。
想象一下两个工程师在同一个团队中。 工程师 A 得到一个特性。 她看了看问题,考虑了几种选择,然后选择了最简单的。 一种直接的实现,可能是 50 行代码。 容易阅读,容易测试,容易让下一个人来接手。 它工作了。 她在几天内就完成了并继续工作。
工程师 B 得到一个类似的特性。 他也看了看问题,但他看到了一种更“健壮”的机会。 他引入了一个新的抽象层,创建了一个 pub/sub 系统来让组件之间的通信,添加了一个配置框架,使特性在未来使用的用例中“可扩展”。 这需要三周。 有多个 PR。 有很多激动的表情符号当他分享了所有这些的文档时。
现在,晋升时间来临了。 工程师 B 的工作几乎可以写入一个晋升包:“设计和实现了一个可扩展的事件驱动架构,引入了一个可重用的抽象层被多个团队采用,并构建了一个配置框架使未来可扩展性。” 这几乎是 Staff+ 的口号。
但对于工程师 A 的工作几乎没有什么可以说。 “实现了特性 X。” 三个词。 她的工作更好。 但它是不可见的,因为她使它看起来很简单。 你无法写出一个令人信服的故事关于你 没有 建造的东西。 没有人因为避免了复杂性而升职。
复杂性看起来很聪明。 不是因为它是聪明的,而是因为我们的系统设定了奖励它的方式。 并且,激励问题并不是在晋升时开始的。 它是在你甚至得到工作之前就开始了。
想想面试。 你在系统设计轮中,提出了一个简单的解决方案。 一个单独的数据库,一种直接的 API,可能是一个缓存层。 面试官会说:“那么,什么是可伸缩的? 如果你有十万个用户?” 所以你添加了服务。 你添加了队列。 你添加了分片。 你在白板上画了更多的盒子。 面试官终于满意了了。
你刚刚学到了复杂性会让人印象深刻。 简单的答案不是错误的。 它只是不够有趣罢了。 并且你可能会把这个教训带到你的职业生涯中。 说实话,面试官有时候会有好的理由来推动规模;他们想看看你在压力下是如何思考的,是否理解分布式系统。 但当候选人学到的教训是“简单不够”,那就有问题了。
它也出现在设计评审中。 一位工程师提出了一种清晰的简单方法,得到的回应是:“我们应该为未来的问题做好准备吗?” 所以他们回去添加了他们不需要的层次,抽象出了可能永远不会出现的问题,添加了可伸缩性以满足没有要求的需求。 不是因为问题要求它,而是因为房间里的人期望它。
我已经 看到工程师 (并且自己也是) 为避免重复几行代码而创建了抽象层,结果使代码更难理解和维护。 每次,感觉都是正确的。 代码看起来更“专业”。 更有工程性。 但用户并没有因为这个而得到特性更快,下一个工程师要接触它时都要花半天时间来理解抽象层才能做出任何改变。
现在,让我明确一下:复杂性有时是正确的选择。 如果你处理了百万笔交易,你可能需要分布式系统。 如果你有 10 个团队在同一个产品上工作,你可能需要服务边界。 当问题复杂时,解决方案(可能)也应该是复杂的!
问题不是复杂性本身。 是未经证实的复杂性。 有一个区别: “我们正在达到数据库限制,需要分片” 和 “我们可能在三年内达到数据库限制,所以我们现在就分片吧”。
一些工程师理解这一点。 当你看他们的代码(和架构)时,你会想:“好吧,当然了。” 没有魔法,没有聪明的东西,让你觉得自己不理解它。 而这正是问题所在。
实际上,晋升的道路 不是学习更多工具和模式,而是学习何时不使用它们。 任何人都可以添加复杂性。 需要经验和自信才能避免它。
那么,我们实际上要做什么呢? 因为说“保持简单”很容易。 改变激励结构更难。
如果你是工程师,学习使简单性可见。 工作本身不会说话;不是因为它不好,而是因为大多数系统都没有被设计来听它。
从你谈论自己的工作开始。 “实现了特性 X” 不意味着什么。 但 “评估了三种方法,包括事件驱动架构和自定义抽象层,确定了最简单的实现满足了当前和预计的要求,并在两天内以零事故的状态交付了六个月” ,这是一样的简单工作,只是用一种能捕捉到它背后的判断的方式来描述。 不建造东西是一种决定,一个重要的决定! 文档它。
在设计评审中,当有人问“我们应该为未来的问题做好准备吗?” 时,不要只是屈服并添加层次。 尝试: “这里是添加它以便在需要时添加它的成本和这里是我们现在添加它的成本。 我认为我们等待。” 你不是推回,而是展示你已经做了功课。 你考虑了复杂性,并选择不采取它。
是时候和你的经理谈谈了。 something like: “我想确保我对我的工作的描述反映了我做出的决定,而不是我写的代码。 我们可以谈谈如何为我的下一次评估框架它吗?” 大多数经理都会欣赏这一点,因为你让他们的工作更容易。 你给他们语言来为你辩护。
现在,如果你做了所有这些,但你的团队仍然只晋升了那个建造了最复杂系统的人……那也很有用。 这告诉你关于你工作的地方。 有些文化真正值得简单。 其他人说他们值得,但奖励的是相反的。 如果你在第二种情况下,那么你要么玩游戏,要么找到一个地方,好判断被真正认可。
如果你是工程领导,这更是你的责任。 你设定了激励,是否意识到它或不。 问题是大多数晋升标准基本上是设计来奖励复杂性的,即使他们不打算这样做。 “影响”被测量为某人建造的大小和范围,更多的时候它确实很重要! 但他们避免的东西也应该很重要。
所以从改变你问的问题开始。 在设计评审中,代替“我们考虑了可伸缩性吗?”,尝试: “最简单的版本是什么我们可以交付,什么具体信号会告诉我们我们需要更复杂的?” 这个问题改变了游戏:它使简单性成为默认值,并将复杂性证明的责任放在复杂性本身身上!
在晋升讨论中,推回当有人包中基本上是一份令人印象深刻的系统清单。 问: “所有这些都必要吗? 我们实际上需要一个 pub/sub 系统在这里吗,还是它只是纸上谈兵?” 并且当你的团队中有人交付了清晰的简单工作时,帮助他们写出故事。 “评估了多种方法,包括事件驱动架构和自定义抽象层,确定了最简单的实现解决了问题” 是一个令人信服的晋升案例,但只有当你实际上对它进行了处理时才会如此。
最后一件事:注意你公开庆祝什么。 如果你的团队频道中每个大声宣扬的都是大型复杂项目,那么人们就会优化它。 开始承认删除代码的人。 那个说“我们不需要它”并正确的人。
归根结底,如果我们一直奖励复杂而忽视简单,那么当我们得到的恰恰是复杂时,我们不应该感到惊讶。但解决办法并不复杂。我想,这正是关键所在。