软件工程公理

软件工程的25条公理

1. 变化是一直存在的

这个应该不会有太大的争议。几乎所有的东西都在不断变化,包括变化本身。我们不仅要承认我们应对变化的能力至关重要,而且要承认我们应对变化的能力如何(时间、成本、质量、可靠性)往往是我们竞争力的一个维度。

2. 你的产品是一种资产,但代码是一种负债

你的产品解决了客户的问题,因此是你的资产。代码本身就是创造资产的成本。你的代码越多,就越需要被阅读、测试、修改和理解。当你考虑到公理1.保守地接受新代码(以及对外部代码的依赖)时,这一点尤其重要。最好的代码是你不需要写的代码。

3. 重复比过早的抽象化成本更低

在你有高度的信心,相信你的抽象会收回成本,因为它解决了你真正有的一个真实的、抽象的问题之前,不要这样做。等待并学习更多。在那之前,重复代码可以帮助避免依赖性,而依赖性本身就使代码更容易独立修改或删除。过早的抽象会通过依赖性和间接性造成复杂性,并且会成为你应对变化的瓶颈。

4. 好的代码是易于删除的代码

写代码要可删除,这在很大程度上和说"解耦"是一样的。当然并不是所有的代码都需要类似的可删除,但是尽量减少依赖关系,通过定义好的接口来明确边界,并有一个周密的整体系统设计,可以让部分代码更容易被删除/更改。我曾经听到有人用"花掉的代码"这个说法,作为"写的代码"的替代,我很喜欢这个说法。我喜欢这样的含义,即删除代码就是减少未来的成本。

5. 现有的代码具有强大的影响力

它存在的事实表明它是正确的和必要的。希望它是正确的,但并非总是如此。我们既要保持改变它的信心,又要有能力去推理是否应该改变它。不要因为代码本身的存在而产生不能删除的怀疑。根据公理4,它应该很容易被删除,而且系统设计应该足够好,让我们能够理解我们是否还需要它。

6. 意外的复杂性是最大的风险之一

意外复杂度是指可以避免的复杂度,其发生的原因是由于设计不当、决策失误,以及没有在系统中优先考虑适当的简单程度。如果简单性不是目标,那么随着系统的发展,意外复杂性更容易发生,并且会逐渐对从改变系统到甚至能够理解系统等几乎所有事情产生负面影响。2006年的论文《Out of the Tar Pit》是一篇值得阅读的文章。

7. 技术上的优秀会被糟糕的个人技能所掩盖

除非你完全是一个人工作,否则重要的不仅仅是你解决技术问题、写好代码等能力。恰恰相反,如果你让周围的人不开心,降低了工作效率,这些就更不重要了。就像学会写好代码一样,你也要学会"对人"好。同理心是其中很重要的一部分,认识到人与人的不同也是很重要的一部分–要有爱心,要善解人意,要帮助别人,自己也要寻求帮助,要对人好。做一个别人愿意合作的工程师。

8. 你不是你的代码。善待编码者,而不是代码

代码只是捕捉了我们认为自己对某件事情了解的一个瞬间。它不是你。你可能写了它,但从那一刻起(即使是3分钟前),你已经成长了,但代码没有。关于代码的对话,无论是好的还是坏的,都不应该是个人的。保持它的专业性。谈论代码,或者谈论问题,但不要把它变成关于写代码的人。使用"我们"而不是"你"。有时我试着假装是我写了别人写的代码,这有助于我避免不小心听起来像个人。

9. 用尊重和耐心对待比你了解得少的人

我们都是从某个地方开始的,当你周围都是有耐心的人,他们希望你成功,而不是那些让你觉得自己不属于自己的人,这个旅程会更快乐。如果你为此而苦恼,记住新手程序员几乎肯定比你做得更好,也许他们精通另一门语言,或者厨艺惊人,或者从事一项运动,也许会有所帮助。想象一下你自己处于相反的角色。你希望他们如何对待你这个完全的新手?再次强调:做一个别人愿意合作的工程师。

10. 唯一真正的权威来自于知识,而不是职位

知识和对问题、领域、客户的理解,都比你名片上的前三个字母重要得多。即使它确实有水印。从第一原则出发,了解某件事情的运作方式,建立扎实的理解,权威就会随之而来。

11. 教学是一种变相的学习

如果你认为你知道什么,就试着教它。通常,试图向别人解释你所知道的东西的行为本身,就会迫使你更清楚地正式确定自己的想法。把事情写下来似乎也有类似的效果。我已经数不清有多少次我开始解释某件事情,却发现我并不像我想象的那样理解它。

12. 提升身边人的技能,而不仅仅是自己

一个伟大的团队绝不是因为一个了不起的人而伟大。这是一个伟大的团队,因为每个人都互相挑战,大家一起成长。当你学到一些很酷的东西时,分享它–帮助你周围的人变得更好。当他们也这样做的时候,每个人都会受益,没有人会被落下。这也更有趣。次要好处:公理11。

13. 你等待的时间越长,你就会知道的越多

我仍在学习这一点,并努力避免我几乎默认的快速决定的欲望。事实上,你拖延非必要决定的时间越长,当你要做决定的时候,你就有更多的信息可以依靠。当然,你不能总是拖延决定,但往往你可以,至少你应该考虑现在不知道答案是否真的可以。

14. 一个好的类型系统是值得它的重量加上一些

在我的职业生涯中,我前后经历了各种静态和动态语言,目前我认为,一个好的类型系统是值得它的开销的。一个好的类型系统不应该承担那么多的开销。如果类型系统设计得好,它几乎可以让人感觉像一门动态语言(通过推理和流分析等特性),同时消除了编译器可以比你更好更快地处理的一类问题。Rust中像所有权这样的发展就是一个很好的例子,说明这一点比人们多年前想象的还要进一步。

15. 正确的团队胜过其他一切

拥有一个只想一起工作并建立伟大事物的团队,会使许多其他问题更容易处理。这里的"合适"一词是高度主观的,也是根据具体情况而定的,但至少从轶事来看,同理心、尊重和友谊是我参加过的优秀团队中经常出现的元素。

16. 坚持使用无聊的技术,除非有充分的理由不这样做

无聊的技术往往比较老,也比较好理解。有如何有效使用它的战斗经验,更好地理解它的失败模式,并且更容易找到如何最好地应用它的人和资源。我非常喜欢Dan McKinley的创新代币的想法。你只有3个。用它们来采用或建立全新的东西–最好是能让你在核心竞争力方面做得更好的东西–但如果超过3个,永远达不到稳定/成熟的风险就会开始增加。

17. 坚持小团队,小心地对待团队成长

这是对一句名言的发挥,你的里程数可能会在这句话上有所不同。在我迄今为止的职业生涯中,我可靠地看到小团队比大团队更有效。当然,要找到一个平衡点,这取决于你要解决的问题的规模和复杂性。也就是说,较小的团队得益于较少的沟通开销,较少的误解空间,以及更多的空间让每个人的声音被听到。在一个小团队里,也会让人感觉更个人化,我觉得责任更大,我喜欢这样。

18. 休息

我很高兴地看到"要想成功,就必须全身心地工作"的态度逐渐去性别化,人们对心理健康和幸福的关注度大大提高。当你感觉不到休息时,你很难感觉到快乐,而当你感觉不到快乐时,你更难做到最好的工作。为了以最佳状态工作,我们必须花时间不工作。我喜欢把休息看作是我工作能力的一个关键部分,就像体育锻炼一样。

19. 在你至少想到一个解决方案之前,不要选择一个解决方案

当那个东西在你的脑海里咔嚓一声,你意识到你找到了解决问题的方法时,是很诱人的,很兴奋的。也许对于一个微不足道的问题,那是很酷的,真的没什么可做的了。但是,如果问题非琐碎或重要,值得考虑的是,可能还有其他你根本还没有想到的解决方案。

为了避免在从无解到有解的兴奋中得意忘形,只是简单地按照你脑海中想到的第一件事去做,试着再想至少1个办法。试图找到第二种解决方案,往往会迫使你进行不同的思考,一旦你有了两种解决方案,你就会被迫考虑如何取舍,以便选择一种。这种对比性的取舍往往也能帮助你更清晰地构筑问题的框架。

20. 有意见,但要避免以导致他人认为你不会改变意见的方式表达

表达我们的信念和意见很重要,我们都应该有这样的空间。然而,在分享意见和听起来好像你在分享一个不可动摇的事实之间有一个微妙的界限。在一个团队中,让每个人都觉得自己可以挑战一个观点,并有可能改变它,或者改变自己的观点,这是非常健康的。

我收到的一个很好的建议,可以帮助解决这个问题,那就是表达你的信念,同时附上你的肯定程度的百分比。“我有95%的把握使用Visual Basic是个坏主意。” 即使是95%,这既是一个开放的机会,让别人质疑这个信念并创造一个对话,也是一个机会,让你在了解到新的信息时简单地修正你的确信。

21. 可以说"我不知道"或"我需要研究一下才有答案"

说实话,我们都不知道自己在做什么。你有吗?好吧,我不知道。我们的行业发展很快,虽然有很多新的旧事物,但也有很多健康的新事物。我们每天都在学习,没有答案是绝对没有问题的。我们的价值不在于我们有能力知道一切,而是我们有能力去学习,去发现,去回答这些问题,去创造新的问题。

当有人告诉我"我不知道"的时候,我很兴奋,因为现在我知道我们可以一起探讨问题,都能学到一些东西。不要藏着掖着,好像只有你不知道一样。往往没有人知道,但你的坦诚只是让大家能够公开地加入进来,一起努力。

22. 为探索问题空间而编写即用即弃的代码是被低估的

比起尝试第一次就把它做对,几次就完全错了,重新开始会更快。有时候,探索问题的最好方法是通过非常接近问题的方式来搞,并尽可能多地学习。

也许你还没有真正理解问题空间,但通过尝试一些事情,你可以发现一些关于设计的高层次对话,或者阅读文档会完全忽略的东西。你可以自由地犯很多错误,最后全部扔掉,你可以很快地学到东西。

23. 认真管理状态

每个程序都有状态,但如何管理状态会产生天壤之别。状态管理不善是导致整个系统复杂度的一个巨大因素,发生这种情况往往是因为没有足够早地考虑到它,在它成长为一个更糟糕的问题版本之前。

有很多不同的策略可以提供帮助,从在给定环境中处理状态的特定方法,到使用功能语言和/或方法围绕状态如何变化创建更严格的约束。无论你做什么,都要慎重对待系统中的状态如何变化。

24. 这是所有关于权衡的问题

几乎你所做的每一个决定,你都在有意或无意地用一件事换取另一件事。有时候,取舍是显而易见的,但有时候,它们与我们眼前能看到的东西却隔着一层。如果取舍不是很明显的话,要时刻思考取舍可能在哪里。

我想到的一个好例子是围棋。Go有一个相当糟糕的类型系统(目前),而且它是一个微小的语言。有什么折衷办法呢?由于它的大小,以及对fanciness的有限支持,我的代码看起来就像你的代码,而且我读别人的代码时,比以前少了"哇,我需要尽快重写这个"的感觉,而且我觉得效率高多了。总会有一些地方是需要权衡的。寻找它,你就能做出更好的决定。

25. 一个好的设计是你可以改变你的想法而不需要改变太多的代码

根据公理1,变化是不变的。这意味着我们需要很好地处理不断变化的条件才能成功–不仅仅是发生在我们周围的、带着我们一起走的外部变化,还包括来自支点、新功能、扩展挑战等的内部变化。

一个好的系统设计应该尽可能地适应我们改变处理问题方式的需要,而不强迫我们从头开始。换句话说,我们需要改变或删除的部分越少(根据公理4,这应该是很容易的),我们在面对变化时就能更快地行动起来;设计就越好。

----本文结束 感谢您的阅读----