我总结了一些软件开发原则。这些原则大多以简化系统为核心。在我看来,一个简单的系统将更加可靠,更容易修改,并且通常更容易使用。当我的想法改变时,我想更新它们。
1
消除无效状态。
我把这一点放在第一位,因为我认为这是最重要、最强大的原则之一。
这个词在定义类型时可能听到过,但实际上这一原则适用于所有与表示数据相关的地方——比如数据库设计。
它不仅可以减少系统的状态数量(从而变得更简单),还可以减少无效状态的数量!您的系统不需要处理这些无效状态,因为它们实际上不能在您的程序中显示。
这不仅仅是一个小技巧,它可以极大地简化你的系统,防止各种类型的bug。
2
数据一致性使系统更加简单。
对数据施加一致性规则,减少系统需要处理的状态数量。这是从上一个原则中衍生出来的。
定义
这是一致性的一般含义:数据遵循某些规则,并始终在任何时候遵循这些规则。这个定义与ACID有关,但不要与CAP混淆。
规则可以是任何东西。例如,您的信用永远不会变为负数,或者其他人不应该看到私人帖子。它不限于外键或唯一索引,尽管它们也是有效的规则。
与数据库一样,应用程序也可以通过使用ACID事务来加强一致性。最好是在数据库级别上保持一致性,但在实践中,这对于稍微复杂的事情来说并不常见。
实用建议
任何限制或破坏一致性的行为都会导致复杂性。这就提出了以下实际建议:
使系统更:
更少的数据库(理想情况下是一个)
标准化,减少冗余数据。
一个好数据库设计。
ACID事务。
更多的数据约束。
使系统更加复杂:
多个数据库
冗余或非标准化数据。
数据库设计不好。
数据约束较少(或没有)。
当然,有时候也有正当的理由让系统变得复杂。我不希望复杂性变成一个肮脏的词。请参考下面的原则不要用牛刀杀鸡。
我认为这一原则是当今软件工程中最被低估的原则之一。一致性问题经常被忽视。很多问题,我敢说,大多数问题基本上都是一致——数据不符合一些期望。
参见附录,了解不一致是如何导致复杂性的。
3
先行数据设计。
这个问题,代码还是数据?
代码可以丢失和重写,但数据很少。
数据比代码更重要。代码的唯一目的是转换数据。
在设计新系统时,最好从数据库和数据结构开始,并在此基础上开发代码。理想情况下,通过表达数据来考虑可以应用于数据的约束和实现。
代码设计是数据设计的下一步。数据模型越简单,代码就越简单。
你给我看流程图,但是当你把表藏起来的时候,我很困惑。如果你给我看你的表,我通常不需要你的流程图,这是不言而喻的。-fredbrooks。
不好的程序员关心代码。良好的程序员关心的是数据结构和它们之间的关系。-Linustorvalds,Linux之父。
4
不要用牛刀杀鸡。
这是软件开发人员最常犯的错误。
这一原则意味着,在权衡需要付出复杂性的成本时,要确保权衡的必要性得到经验证据的支持。
常见错误:
试图构建一个复杂的可伸缩系统,可以扩展到你可能永远不需要的规模。
使服务尽可能小,不考虑需求或成本。
优化性能,增加不一致性或复杂性。
建议:
尽量从最简单、最正确的系统开始。
测量性能。
如果实际问题无法解决,不要付出复杂的代价或违反其他原则。
有些优化无法衡量,因为它们的成本非常低或为零。例如,使用正确的数据结构,以确保您想要执行的操作具有您想要的性能。
的确,有时候经验本身就能告诉你是否做出了正确的权衡。但是如果你能证明的话,那就更好了。
当你必须做出选择时,请选择正确性和简单性,而不是性能。
在某些情况下,正确而简单的代码是性能最好的代码!
真正的问题是,程序员花太多时间在错误的地方和错误的时间上担心效率。早期优化是编程中所有罪恶的根源(或至少大多数)。-计算机科学家。
5
避免为局部简单性增加全局复杂性。
也就是说,避免整个系统变得更复杂,以使系统的一部分更简单。
这种交换通常是不平等的。对局部简单性的追求会导致整体复杂性的增加,而且是数量级的。
例如,使用较小的服务可以使这些服务变得更简单,但是减少一致性和需要更多的过程间通信使系统更加复杂。
6
识别内部复杂性。
有时候事情本身就很复杂,你不能简化问题。
任何这样的尝试都只会使系统更加复杂。
7
使用的技术越少,系统就越简单。
对一小部分技术的深入理解比对许多技术的表面理解要好。
更少的技术意味着更少的东西需要学习,更少的操作和维护复杂性。
8
专注于学习概念,而不是技术。
不要过分关注技术的复杂细节,因为你可以随时查阅它们。你必须学习基本概念。
技术会改变,但这个概念是永恒的。在更新的技术中使用你学到的概念,你可以更快地学习新技术。
例如,不要过分关注React、Kubernetes、Haskell、Rust。
重点学习:
纯函数式编程。
关系型模型
规范的方法
逻辑编程
代数数据类型。
类型(通用和特定)
借位检查员(仿射/线性类型)
依赖类型
HowardCurrry。
宏
(homoicoicicity)
Virtualdom。
线性回归
...
9
代码一致性很重要。
有时,一致性代码比正确代码更重要。如果要更改代码库中某些代码的行为,请修改所有示例。否则,你只能忍受。
代码的可读性更多地与一致性(而不是简单性)有关。人们通过模式识别来理解代码,所以请重复(和记录)模式!
10
共享原则很重要。
如果你和队友之间有更多的共同原则,你就能更好地一起工作,你就会更喜欢和他们一起工作。
11
附录:由不一致性引起的复杂性。
这是我能想到的最简单的例子,希望能与实际问题毫不费力地联系起来。
假设一个数据库有两个布尔变量x和y,你的应用程序有一个规则,即x=y,可以通过使用一个事务来修改这两个变量来执行这个规则。
如果正确执行这一规则,数据只有两种状态:(x=true,y=true)或(x=false,y=false)。
基于这一规则的函数toggle非常简单。您可以读取其中一个值,并将两个值设置为反向值。
现在,假设你把这两个变量放在不同的数据库中,不能一起修改,会发生什么?
数据可以有两种以上的状态:(x=true,y=false)或(x=false,y=true),因为你无法保证x=y的一致性。
如果您的系统处于这些状态之一,您应该使用哪个值?
toggle函数的行为是什么?
在写入新值时,如何保证两次写入都成功?
没有正确答案。
当然,如果我们从一开始就遵循消除无效状态的原则,那么只有一个变量!