理念

在计算机科学的发展史上,有许多思想和理念,产生了深远的影响。

学而时习之,不亦说乎

子曰:学而时习之,不亦说乎!有朋自远方來,不亦乐乎!人不知而不愠,不亦君子乎!

经常学习,不也喜悦吗?从远方来了朋友,不也快乐吗?别人不了解我也不怨恨,不也是君子吗?

学说和实践互相印证、促进,这不快乐嘛?不同学说的人前来探讨、考察,这不快乐吗?有人反对、不认可,也不心生怨念,我就该这样啊。

技术更新一日千里。选择适合自己的技术,了解别人的技术,互通有无。

编程,我们要选择适合自己的技术。选择的过程是一个每日实践的过程。

吾生也有涯,而知也无涯

庄子:吾生也有涯,而知也无涯。以有涯随无涯,殆已;已而为知者,殆而已矣。

人的生命是有限的,而知识是无限的,以有限的生命追随无限的知识,要完。明知如此,仍要去求“知”,更要完。

技术众多。如果我们毫无选择的去学习,去采用,最终会纠缠其中,不得要领。

在编程中,我们要厘清需求,再择技术,有针对的去用。

随机数与伪随机数、偶然与必然

计算机采用软件方式生成的随机数是“伪随机数”。计算机本质上是确定性的,无法生成真正的随机数。

有一种生成方式是采用硬件获取外部的噪音生成随机数。

伪随机数(Pseudo-Random Numbers)

  • 伪随机数是通过算法生成的,这些算法(如线性同余生成器、梅森旋转器等)基于一个初始值(种子)来生成数字序列。这个序列在统计上看起来像是随机的,但实际上是完全确定的。如果知道算法和种子,就能预测出所有的数字。
  • 计算机通常生成的是伪随机数。这些数可以快速且一致地生成,对于大多数应用来说足够“随机”。

真随机数(True Random Numbers)

  • 真随机数的生成依赖于物理过程,这些过程本质上是不可预测的,如放射性衰变、热噪声、光噪声等。
  • 真随机数生成器(TRNGs)需要专门的硬件来捕捉和转化这些物理过程的随机性。

对于大多数应用来说,伪随机数足够好,因为它们能提供良好的统计特性,且易于控制和重现。在一些特定领域,如密码学和高级安全应用,需要真随机数来确保最高级别的不可预测性和安全性。

存在真随机数?

如果物理定律是确定的,理论上依赖于这些物理过程的随机数生成也应该是确定的。

经典物理学的确定性。

在经典物理学的框架下,物理过程被认为是完全确定的。如果我们知道了所有相关的初始条件和物理定律,理论上我们可以准确预测任何物理系统的未来状态。但在实际应用中,由于初始条件的复杂性和测量的不精确,预测具体事件(如掷骰子的结果)仍然具有不确定性。

量子力学的不确定性

  • 在量子力学中,即使是在完全已知的初始条件下,某些事件的结果也具有根本性的不确定性。例如,量子叠加和量子纠缠等现象意味着即使在理论上也无法准确预测个别量子事件的结果。
  • 基于量子过程的随机数生成器(如使用量子噪声或量子纠缠的设备)利用这种根本性的不确定性来产生真随机数。

当我们说一个基于物理过程的随机数生成器是“确定的”时,我们是指在经典物理学的范畴内。但在量子力学层面,即使物理定律是确定的,某些物理过程本身就是不确定的,从而能够产生真正的随机性。

不可预知≠随机

量子力学的不确定,是由于真的不确定,还是由于测量水平或认知水平导致的无法根据已知条件推断结果产生的不确定性?

几百年前我们无法准确的预知日食,在那个年代,日食被认为不确定。但随着物理学的不断推进,到现在日食是可以被预知的。

物理世界的确定性与自由意志

物理世界的确定性

在物理学中,尤其是在经典物理学领域,世界被视为一个确定的、机械的系统。在这个框架下,如果知道了所有初始条件和自然定律,理论上可以预测未来的状态。然而,量子力学引入了不确定性的概念,即在微观层面,事件的结果具有根本性的随机性。然而,即使在量子层面存在不确定性,它是否影响宏观世界(如人类行为)仍然是一个开放的问题。

自由意志的存在

  • 自由意志是指个体在没有外部强制的情况下做出选择的能力。在哲学和神经科学中,关于自由意志的本质存在着广泛的讨论。一种观点认为,如果我们的行为完全由大脑中的神经活动决定,而这些神经活动又受到遗传和环境的影响,那么自由意志可能只是一种幻觉。
  • 另一方面,有理论认为,尽管我们的决策受到多种因素的影响,但人类仍然有能力在一定程度上自主地做出选择。这个观点认为,即使在确定的物理环境中,个体也能展现出一定程度的自由意志。

三体世界中的偶尔与必然

在刘慈欣的小说《三体》中描述了一个三体文明,该文明的主要工作是让“随机”的三体问题产生确定性。”三体问题”指的是一个在天体力学中的问题,描述了在引力作用下,三个质点之间相互运动的复杂性。

具体来说,这个问题考虑的是三个质点之间只受引力相互作用,并且初始时它们的位置和速度都是已知的。然而,尽管这个问题看似简单,却在一般情况下无法精确求解。

  • 非线性性:三体问题的方程是非线性的,这意味着质点之间的相互作用不是简单的线性关系。非线性方程组的解通常难以用封闭形式表示。
  • 混沌性:三体问题具有混沌性质,即微小的初值差异可能会导致长期的、不可预测的运动。这使得随着时间的推移,系统的行为变得极其复杂,难以准确预测。
  • 无法找到通解:比较简单的两体问题有解析解,但三体问题的解析解在一般情况下是不存在的。这是因为三体问题涉及到更多的自由度和复杂的相互作用,难以找到通用的数学表达式。

尽管一般的三体问题难以解决,但在一些特殊情况下,比如限制性三体问题(其中一个质点质量很小)可以找到一些近似解。这些特殊情况通常对实际问题的简化程度要求较高。

从三体的故事中我们可以发现:复杂度可以决定是否可预知性,但是不代表随机性。

随机数的性质

随机数的性质大概可以分成3种,分别是随机性、不可预测性和不可重现性。它们的定义如下:

  • 随机性:不存在统计学上的偏差,是完全杂乱无章的数列。
  • 不可预测性:无法从过去的已经生成的数列中推测出下一个数。
  • 不可重现性:对于过去出现的数列,以后不会再次出现相同的数列。

这三种特性可以看作是对随机数的约束条件。其中,随机性的约束最弱,不可重现性的约束最强。具备不可重现性,则一定具备不可预测性和随机性。具备不可预测性,则一定具备随机性。简言之,后者是前者的充分非必要条件。

根据约束的强弱,我们把满足上述三种特性的随机数依次称为“弱伪随机数”,“强伪随机数”,“真随机数”。如下表格。需要注意的是,应用在安全系统中的随机数至少具备不可预测性。就是说,弱伪随机数是不能用在安全系统中的。

名称\特性随机性不可预测性不可重现性备注弱伪随机数☑️✖️✖️不可用于安全系统强伪随机数☑️☑️✖️可用于安全系统真随机数☑️☑️☑️可用于安全系统

计算机随机数生成原理

伪随机数生成器(PRNGs)的发展经历了多个重要的版本和改进,这些版本反映了计算机科学和数学理论的进步。下面是一些主要的发展阶段:

  • 线性同余法 (Linear Congruential Generator, LCG)
    • 早期伪随机数生成算法之一。
    • 算法使用线性同余的形式,通过乘法和加法操作生成下一个随机数。
    • 简单但容易受到周期性和统计特性的限制。
  • 梅森旋转算法 (Mersenne Twister):
    • 1997年由松本眞等人提出。
    • 使用一个大的梅森素数作为周期,提高了周期性和统计特性。
    • 在许多应用中广泛使用,被认为是高质量的伪随机数生成器。
  • Park-Miller-Carta伪随机数生成器:
    • 1988年由Park和Miller提出。
    • 使用2^31-1作为素数周期,成为C语言标准库rand函数的实现基础。
  • XORshift算法
    • 2003年由George Marsaglia提出。
    • 通过位运算的异或操作实现快速且高质量的伪随机数生成。
    • 相对于一些传统方法,它的周期性较好。
  • PCG (Permuted Congruential Generator)
    • 2014年由Melissa O’Neill提出。
    • 结合了线性同余法和置换操作,提供了更好的统计特性。
    • 具有良好的性能和周期性,广泛用于游戏和模拟等领域。

线性同余法 (Linear Congruential Generator, LCG)

线性同余生成器是一种简单的伪随机数生成算法。其基本原理是通过线性方程来生成一系列的数字,这些数字表面上看起来是随机的,但实际上是完全确定的。这种方法广泛用于计算机程序中的伪随机数生成。

线性同余法是一种简单的伪随机数生成方法,其基本思想是通过一个递推式,每次生成下一个伪随机数。具体来说:

  • 初始化:选择一个初始值(种子),通常用于设置随机数生成的起点。
  • 递推式:使用线性同余的递推式,将当前随机数转换为下一个随机数。典型的递推式形式是:Xn+1=(a∗Xn+c)Xn+1=(a∗Xn+c)。其中,XnXn是当前随机数,a是乘法因子,c是增量,m是模数(确定生成的范围)。
  • 重复:不断使用递推式生成新的随机数。

重要的是选择适当的参数,以避免出现很短的周期、重复性或其他统计不足的问题。常见的选择包括使用大素数作m,选择适当的a和c,以及合理的初始种子。

在早期的C语言编程中,一个基本的线性同余生成器(LCG)可以用以下方式实现:

#include <stdio.h>// 定义线性同余生成器的参数unsigned long a = 1103515245;unsigned long c = 12345;unsigned long m = 2147483648; // 2^31unsigned long seed = 0; // 种子// 线性同余生成器函数unsigned long lcg() { seed = (a * seed + c) % m; return seed;}int main() { // 设置种子值 seed = 123; // 可以设置任意初始种子值 // 生成随机数 for (int i = 0; i < 10; i++) { printf("%lu\n", lcg()); } return 0;}

a、c和m是线性同余生成器的参数,这些值的选择会影响随机数序列的质量。seed是初始的种子值,不同的种子值会产生不同的随机数序列。lcg()函数实现了线性同余生成器的主要算法。在main()函数中,我们通过调用lcg()函数来生成一系列的伪随机数。

在提供的代码中,seed的初始值为123,这个值会被lcg函数使用。在lcg函数中,每次调用时,都会根据当前的seed值计算下一个随机数,并更新seed的值。这意味着,lcg函数的输出(即生成的伪随机数)依赖于seed的当前值。

在选择线性同余生成器(LCG)的参数a, c, 和m 时,目的是为了确保生成的伪随机数序列具有良好的统计特性,比如较长的周期和较好的均匀性。选取这些参数的原则包括:

  • 模数m: 通常选择为2的幂,例如231231或232232,因为这可以简化取模运算,使其更适合于计算机处理。更大的m值通常可以产生更长的周期。
  • 乘数a和增量c: 这些值需要仔细选择,以确保随机数生成器有着良好的统计特性。存在一些经验法则和理论准则用于选择a和c。例如,Knuth提出的一些选择准则是:
    • a-1可以被m的所有素因子整除。
    • 如果m是4的倍数,那么a-1也应该是4的倍数。
    • c和m应该是互质的(即最大公约数为1)。

a-1可以被m的所有素因子整除

要理解”(a-1)可以被(m)的所有素因子整除”这一准则,我们需要先了解素因子和线性同余生成器(LCG)周期性的概念。

  • 素因子:一个数的素因子是指能整除这个数的素数。例如,数12的素因子包括2和3,因为12可以被2和3整除。
  • 线性同余生成器的周期:线性同余生成器生成的伪随机数序列是周期性的,这意味着序列最终会重复。理想情况下,我们希望这个周期尽可能长,以便生成器能产生更多的不重复的随机数。

现在来看这个准则:(a-1)可以被(m)的所有素因子整除”。这个准则是为了确保LCG能达到最大可能的周期,也就是接近或等于m。这是因为:

  • LCG的周期最多只能达到 m,这是因为它在每一步都是对 m 取模,因此不可能产生超过 m$ 个不同的值。
  • 当 (a-1) 能被 (m) 的所有素因子整除时,它有助于确保每个可能的种子值(从 0 到 m-1)都能在序列中出现,从而使得周期最大化。

简而言之,这个准则有助于确保 LCG 能生成具有较长周期的随机数序列,从而提高了其作为随机数生成器的有效性。但需要注意的是,即使遵守了这个准则,LCG 生成的仍然是伪随机数序列,其随机性和真实随机性相比仍有限。

如果 m 是 4 的倍数,那么 a-1 也应该是 4 的倍数

要理解为什么当模数 m 是 4 的倍数时,乘数 a 减 1 也应该是 4 的倍数,我们需要考虑线性同余生成器(LCG)的周期性和其在特定条件下的行为。

首先,回顾一下线性同余生成器的基本形式:

Xn+1=(aXn+c)modmXn+1=(aXn+c)modm

这里,Xn+1Xn+1 是序列中的下一个数 XnXn 是当前的数,而 a, c, 和 m 是生成器的参数。

LCG 的目标是产生一个长周期的伪随机数序列。为了实现这一点,需要确保该序列能够探索其全部可能的状态空间,即从 0 到 m-1 的所有整数。如果 m 是 4 的倍数,那么要实现这一点,就需要 a-1 也是 4 的倍数。这是因为:

  • 偶数与奇数的混合:当 m 是 4 的倍数时,它能被 2 整除两次,这意味着它包含了较多的偶数。为了确保生成器能够均匀地覆盖这些偶数和奇数,需要 a 的选择能够适应这种结构。特别地,当 a-1 是 4 的倍数时,这有助于保证序列中偶数和奇数的均匀出现。
  • 周期的最大化:与前面的规则一样,这个规则也是为了最大化 LCG 的周期。当 a-1 是 4 的倍数时,它能更好地与 m 的结构相匹配(特别是当 m 是 4 的倍数时),从而帮助序列达到更大的周期。

综上,这个规则帮助确保当模数 m 是 4 的倍数时,LCG 能够更有效地遍历其可能的状态空间,从而产生一个具有较长周期的伪随机数序列。这一点对于确保生成的随机数质量至关重要,尤其是在需要伪随机数具有良好统计特性的应用中。

梅森旋转算法(Mersenne Twister)

梅森旋转算法(Mersenne Twister)是一种广泛使用的伪随机数生成器算法。它由松本真和西村拓士在 1997 年开发,主要特点是具有极长的周期和较高的均匀度。以下是梅森旋转算法的一些关键特征:

  • 极长的周期:梅森旋转算法的一个最著名特点是其极长的周期。最常用的版本 MT19937 的周期为 219937−1219937−1,这是一个梅森素数(Mersenne prime),因此得名。这个周期远远超过了大多数实际应用的需要。
  • 高维度均匀分布:梅森旋转算法能产生高质量的伪随机数,这些随机数在高达 623 维度上均匀分布。这意味着在多维空间中,生成的随机点分布非常均匀。
  • 实现方式:算法基于一个巨大的位移寄存器(通常为 19937 位),使用特定的线性递归公式更新。在每次生成随机数时,它会改变寄存器的状态,从而产生新的随机数。
  • 效率和可移植性:梅森旋转算法在现代计算机上运行效率高,且容易实现,保证了良好的可移植性。它在多种编程语言和系统中被广泛采用。
  • 用途:由于其优良的统计性质和长周期,梅森旋转算法被广泛用于各种需要随机数的应用中,如模拟、计算机图形学和游戏开发。但需要注意,由于它不是加密安全的随机数生成器,不适合用于加密或安全相关的应用。

尽管梅森旋转算法有很多优点,但它也有一些缺陷,比如状态空间较大,且如果初始状态(种子)不当,可能需要较长的时间来”热身”(达到理想的随机分布状态)。此外,由于其算法结构,一旦部分输出被破译,剩余部分也容易被预测。因此,在需要更高安全性的场合,应该使用专为安全性设计的伪随机数生成器。

不同编程语言下的随机算法

目前主流编程语言中自带的伪随机数算法各有不同,以下是一些常见编程语言及其伪随机数算法:

  • C/C++:C/C++ 标准库中的 rand() 函数通常实现了线性同余生成器(Linear Congruential Generator, LCG)。C++11 引入了更多选项,比如梅森旋转算法(Mersenne Twister)。
  • Python:Python 的 random 模块默认使用梅森旋转算法(Mersenne Twister),这是一种常用的高质量伪随机数生成器。
  • Java:Java 在 util.Random 类中默认使用的是线性同余生成器。但是,Java 还提供了其他选择,如 java.security.SecureRandom,这是一个更安全的伪随机数生成器,常用于加密应用。
  • JavaScript:JavaScript 中的 random() 通常是浏览器或 JavaScript 引擎实现的,具体算法可能会有所不同。但多数情况下,它们使用的是伪随机数生成算法,如线性同余生成器或其他类似的算法。
  • Ruby:Ruby 的伪随机数生成通常使用梅森旋转算法。
  • PHP:PHP 在 rand() 和 mt_rand() 函数中使用了不同的算法。mt_rand() 使用了梅森旋转算法,而 rand() 的实现取决于平台。PHP 7.1.0 起,rand() 和 mt_rand() 使用相同的随机数生成器。
  • Go:Go 语言在 `math/rand` 包中提供了伪随机数生成,其默认使用的是一种线性同余生成器。

可以看到线性同余生成器并没有被时代淘汰。包括年龄最小的 Go 语言也在使用。Go 语言标准库中 math/rand 包的 Intn 函数的实现逻辑是基于线性同余生成器(Linear Congruential Generator,LCG)的。

以下是简化版本的 Intn 实现逻辑:

package randvar (// 种子,初始值设为 1seed int64 = 1)// Intn 返回 [0,n) 范围内的伪随机整数。func Intn(n int) int {if n <= 0 {panic("invalid argument to Intn")}// LCG 参数const (a int64 = 1103515245c int64 = 12345m int64 = 2147483648)// 通过线性同余生成器计算下一个伪随机数seed = (a * seed + c) % m// 将伪随机数映射到 [0,n) 范围return int(seed % int64(n))}

随机数的周期性

伪随机数是由确定性算法生成的数列,它们在某种程度上模拟了随机数的性质,但由于算法的确定性,这些数列实际上是可预测的。伪随机数生成器(PRNG)通常基于一个初始值,称为种子(seed),通过数学运算产生数列。

伪随机数的周期性是指 PRNG 在生成数列时最终会重复相同的数列片段。这个重复的数列片段称为周期(period),而整段周期之前的非重复序列部分称为不重复长度。周期性是 PRNG 设计中的一个重要考量因素,因为它决定了生成器的使用寿命和产出数列的随机性质。

周期性的特点包括:

  • 周期长度:一个理想的 PRNG 会有非常长的周期长度,这意味着在重复之前能够生成大量的伪随机数。例如,线性同余生成器(Linear Congruential Generators, LCG)的周期最大为它的模数(modulus),但这取决于选择的参数。
  • 分布均匀性:即使 PRNG 具有长周期,如果数列中的数分布不均,则不适合某些应用。一个好的 PRNG 应该在一个周期内,数的分布尽可能接近均匀。
  • 初始种子:不同的初始种子会导致不同的数列,即便是同一个 PRNG。理论上,一个 PRNG 的不同种子之间的周期不应该重叠,不过实际上这很难做到。
  • 算法复杂度:一些具有长周期和良好统计特性的 PRNG 可能在计算上更复杂,这可能会影响到它们。

以下 PHP 代码在 Windows 不同 PHP 版本下生成的图片:

<?phpheader("Content-type: image/png");$im = imagecreatetruecolor(512, 512)or die("Cannot Initialize new GD image stream");$white = imagecolorallocate($im, 255, 255, 255);for ($y = 0; $y < 512; $y++) {for ($x = 0; $x < 512; $x++) {if (rand(0, 1) === 1) {imagesetpixel(im,im,x, y,y,white);}}}imagepng($im);imagedestroy($im);

Window环境下PHP7.4.28生成的图片:

Window环境下PHP5.6.40生成的图片:

可以看到老版本PHP有明显的周期性,新版本的随机算法使用的梅森旋转算法,周期性更长,所以上面的图片无法显现出来。即如果周期过长,我们无法准确的认知到周期是否存在。

我们是否存在与周期(轮回)中?

要证明我们是否生活在一个周期极长的循环中,是一个复杂且深奥的问题,涉及到宇宙学、哲学和物理学的多个领域。目前,我们没有确凿的科学方法或证据能够完全证明或否定这个假设。

  • 科学观察和证据:至今为止,科学家没有发现任何直接证据表明我们的宇宙或人类历史是周期性的,特别是在超越已知历史长度的周期上。
  • 宇宙学理论:在宇宙学中,有各种理论试图解释宇宙的起源、发展和终结,如大爆炸理论、膨胀宇宙论等。这些理论基于广泛的天文观测和物理定律。尽管有些理论(如多重宇宙理论)提出了宇宙可能具有某种形式的周期性,但这些都是高度理论化的观点,并没有直接证据支持。
  • 哲学和逻辑上的考虑:从哲学角度来看,证明或否定这种大尺度周期性存在的问题类似于证明或否定任何其他无法观察到的假设。如果一个现象无法被观测或测量,那么在科学上验证它是非常困难的。
  • 技术和观测的局限性:目前人类的技术和观测手段有限,我们只能观测到宇宙的一部分,并且只能追溯到大约138亿年前的大爆炸。如果宇宙的周期远远超过这个时间范围,那么我们目前的技术无法探测到这样的周期。

关于我们是否生活在一个周期极长的循环中的问题,目前仍属于高度理论化且未被证实的假设。这个问题的回答可能超出了现有科学知识和观测能力的范畴。

随机数的种子

为了生成伪随机数,计算机程序通常需要一个种子值。这个种子值是由用户提供的初始值,它用于初始化随机数生成器算法。在程序运行过程中,随机数生成器会利用这个种子值来计算下一个随机数。如果种子值相同,生成的随机数序列也将完全相同。

因此,种子值的选择对于生成随机数的质量和随机性非常重要。如果种子值是预测性的,那么生成的随机数序列也可能是可预测的。相反,如果种子值是不可预知的,那么生成的随机数序列也将是不可预知的。

通常,种子值是由系统时间生成的。在某些情况下,开发人员还可以手动指定种子值来生成特定的随机数序列。

指定随机数seed

直接控制种子值以获得可预测的随机数序列,比如在机器学习中拆分训练集和验证集时,为了每次验证随机拆分都都一致,通常也会指定seed。

from sklearn.model_selection import train_test_split# 将数据集拆分为训练集和测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

这里的random_state起始就是seed。如果不使用train_test_split,则可以:

import randomrandom.seed(42) # 设置随机种子为42indices = list(range(len(data)))random.shuffle(indices)train_indices = indices[:int(0.8*len(data))]val_indices = indices[int(0.8*len(data)):]train_data = data[train_indices]val_data = data[val_indices]

假设一个抽奖程序的开发人员想要某个人中奖,就可以采用指定随机数序列的方式。

使用系统时间作为Seed

在计算机程序中,系统时间是一种常用的种子值来生成伪随机数的方法。这是因为系统时间会不断变化,因此可以产生看似随机的种子值。然而,这种方法也存在一些问题。

  • 系统时间存在精度问题,有的是秒,有的是微秒。如果程序在短时间内多次运行,这将导致生成的随机数序列是相同的。
  • 如果不同的电脑在相同时刻生成随机数,则也会出现随机数相同的场景。
  • 攻击者可以通过更改系统时间来影响随机数的生成。例如,攻击者可以将系统时间更改为一个较早的时间,这将导致程序使用相同的种子值来生成随机数,从而使攻击者能够预测随机数的值。

写在最后,我们如何定义我们生活的世界?“缘分”这个既能表示偶然又有表示必然的词可以定义。你能看到这篇文章也是“缘分”。

时代对人的影响:反面例子:卓别林的摩登时代、996时代

摩登时代(工业革命时期)和信息时代(互联网和数字技术的时代)。

《摩登时代》中,故事的主人公是卓别林标志性的角色“小流浪汉”(The Tramp),他在一家工厂里工作,处于流水线的高压环境下。在试图跟上机器的节奏时,他遭受了精神崩溃,因此被送进了医院。

剧中的老板期望流水线越来越快,不断让流水线提速。流水线上的卓别林们不断加快自己的工作节奏。

老板期望减少员工的休息时间,引入自动喂食机器。

最终,工人被机器取代。,影片探讨了自动化对劳动市场的潜在威胁。

《摩登时代》以辛辣幽默的方式揭示了现代化进程的荒诞和无情。

996时代,许多程序员早上9点到办公室,晚上9点离开办公室,每周工作6天。

但实际上,许多公司的程序员晚上是不回家的。夜里就睡在办公室里。

许多程序员因长时间的工作,猝死在办公室。

技术进步,应该减轻人的劳动负担,让人类有更多的时间去享受生活。但实际情况往往更为复杂。

  • 经济结构和就业市场的变化:随着机器和自动化技术逐渐取代一些工作,某些行业的工人发现自己需要转行来适应新的工作环境。
  • 收入分配不均:自动化可以增加生产效率并创造财富,但这些财富并不总是平等分配的。机器的使用主要使得资本拥有者受益,而工人的薪酬并没有相应增长,这可能导致普通工人需要更长时间工作以维持生活水平。
  • 提高的产出预期:即使技术提升了工作效率,个人也可能因为社会标准的提升而感到压力。
  • 竞争与比较:当个体能够通过技术显著提高生产力,社会可能会根据个人的产出和效率相互进行比较和竞争,导致即使在资源丰富的情况下人们也会感到不安全和焦虑。
  • 资源分配:资源的分配可能趋向于更高效率和更高产出的个体或团体,从而在一定程度上影响那些无法达到这些标准的人的社会地位和收入。
  • 工作与生活的平衡:尽管技术发展可能减少了完成某些任务所需的时间,但社会对个人成就的要求可能导致人们将节省下来的时间再投入到工作中,从而牺牲了个人生活和休闲时间。
  • 忽略工作以外的价值:如人际关系、创造力和精神满足等,这些方面对于个人的幸福感和社会的整体健康同样重要。

新技术和无聊的技术

新技术总是让工程师兴奋不已。新的编程范式、新的编程语言、不同的库、不同的数据库。我们总是在寻找新奇并渴望学习,但用户并不关心你的公司使用什么技术。只要你的产品有效,他们就会很高兴。

以下是文章的主要内容和核心观点的解读:

主要内容

  • 技术债务
    • 定义:技术债务是指在软件开发过程中为了快速交付而采取的捷径,这些捷径会在未来导致额外的成本和维护负担。
    • 影响:技术债务会逐渐累积,导致系统变得难以维护和扩展,最终影响业务的发展。
  • 新技术的风险
    • 不稳定性:新技术往往不够成熟,可能存在未发现的 bug 和性能问题。
    • 缺乏文档和支持:新技术的文档和社区支持通常不如成熟技术完善。
    • 学习成本:团队需要花费时间和精力来学习和适应新技术,这会影响项目的进度。
  • 成熟技术的优势
    • 稳定性:成熟技术经过长时间的使用和测试,已经证明了其可靠性和稳定性。
    • 社区支持:成熟的社区可以提供丰富的文档、教程和解决方案,帮助团队快速解决问题。
    • 降低风险:使用成熟技术可以降低项目失败的风险,提高项目的成功率。
  • 案例研究
    • Etsy:Dan McKinley 在 Etsy 工作时,强调了使用成熟技术的重要性。Etsy 的成功部分归功于他们在技术选型上的保守态度,选择了经过验证的技术栈,如 MySQL、Perl 和 Nginx。
    • Netflix:Netflix 虽然在技术创新方面走在前列,但在某些关键系统中仍然使用了成熟的技术,如 Apache Cassandra 和 Amazon Web Services(AWS)。
  • 如何选择技术
    • 评估需求:根据项目的实际需求和技术栈的现状,选择最适合的技术。
    • 风险管理:评估新技术引入的风险,并权衡其潜在的好处。
    • 逐步引入:如果确实需要引入新技术,可以先在小范围内进行试点,逐步推广。

核心思想

  • 稳定性和可靠性
    • 经过时间考验的技术通常更为稳定和可靠。它们已经在各种环境和使用场景中被广泛测试,并且其缺陷和局限性也更为人所知。
    • 选择这些技术可以减少意外问题的发生,提高系统的整体稳定性。
  • 社区支持和文档
    • 成熟的技术通常拥有强大的社区支持和丰富的文档资源。开发者可以更容易地找到帮助、解决问题和学习最佳实践。
    • 丰富的第三方库和工具链也使得开发过程更加高效。
  • 降低风险
    • 使用新兴或未经验证的技术可能带来不可预见的风险,包括安全漏洞、缺乏支持、文档不足以及技术被废弃的可能性。
    • 选择成熟技术可以降低这些风险,使项目更具可预测性。
  • 维护成本
    • 成熟技术的维护成本通常较低,因为它们的生态系统更为完善,开发者在这些技术上的经验也更为丰富。
    • 这可以降低长期的技术债务和维护难度。
  • 人才获取
    • 由于成熟技术被广泛使用,拥有相关技能的开发者更容易找到。这可以降低招聘难度,并加快团队的成长。

核心观点

  • 优先考虑成熟技术
    • 在技术选型时,优先考虑那些已经被广泛使用和验证的技术,而不是追求最新的技术潮流。
    • 成熟技术的稳定性和可靠性可以显著降低项目失败的风险,提高项目的成功率。
  • 避免过度创新
    • 过度追求新技术可能会带来不必要的复杂性和风险,影响项目的进度和质量。
    • 技术创新应该服务于业务需求,而不是为了创新而创新。
  • 平衡创新与稳定
    • 在某些情况下,引入新技术是必要的,但应该谨慎评估其风险和收益。
    • 通过逐步引入和试点,可以在控制风险的前提下,逐步实现技术升级。

实际应用

  • 企业级项目
    • 对于大型企业级项目,选择成熟技术可以确保系统的稳定性和可靠性,降低维护成本。
    • 例如,金融行业通常会选择成熟的技术栈,以确保系统的安全性和合规性。
  • 初创公司
    • 初创公司在资源有限的情况下,选择成熟技术可以加快产品上市速度,减少开发成本。
    • 但在某些特定领域,创新技术可能带来竞争优势,因此需要权衡利弊。
  • 个人开发者
    • 个人开发者在选择技术时,可以根据项目的规模和复杂度,灵活选择合适的技术。
    • 对于小型项目,使用成熟技术可以更快地完成开发;对于大型项目,可以考虑引入一些创新技术来提升性能和用户体验。

《Boring Technology》这篇文章强调了在技术选型和系统设计中优先考虑成熟、稳定的技术的重要性。通过选择成熟技术,可以降低项目风险,提高项目的成功率。然而,这并不意味着完全排斥新技术,而是要在充分评估风险和收益的基础上,合理选择和引入新技术。文章的观点对于企业和个人开发者都有重要的参考价值。

相关想法

1、远离最新最精端技术

在网站/应用开发中,避免使用新技术可能有以下几个原因:

  • 稳定性和可靠性:新技术往往未经充分验证,可能存在未发现的错误或漏洞。使用成熟的技术可以提供更高的稳定性和可靠性,减少潜在的风险。
  • 支持和社区:成熟技术通常拥有更大的用户社区和更完善的支持体系,开发者在遇到问题时更容易找到解决方案。而新技术可能缺乏足够的文档、教程和社区支持。
  • 兼容性:在开发过程中,确保新技术与现有系统和工具的兼容性可能是一个挑战。使用成熟技术可以减少集成和兼容性问题。
  • 学习曲线:采用新技术可能需要团队进行额外的学习和培训,这会增加开发时间和成本。对于时间紧迫的项目,使用团队已经熟悉的技术可能更为高效。
  • 长期维护:新技术的未来发展方向和长期支持可能不明确,选择被广泛采用和支持的技术可以确保项目的长期可维护性。

成本考虑:新技术可能需要额外的投资,包括培训、工具购买以及潜在的技术债务,而成熟技术的成本往往是已知和可控的。

  • 业务需求:如果现有技术能够满足业务需求,没有必要引入新技术增加复杂性和风险。

当然,这并不意味着应该完全避免使用新技术。在某些情况下,新技术可能提供显著的优势,如性能提升或新功能,但在决定采用之前,需仔细评估其潜在风险和收益。

一般来说,如果一个项目已经存在足够长的时间,人们已经遇到了每个问题并分享了每个解决方案。

2、这项技术适合当前业务场景吗?

不同规模的项目和团队对技术的需求是不一样的:

  • 技术适用性:在选择技术时,需要考虑它是否适合你的项目规模和团队能力。某些技术是为处理大规模系统的复杂性而设计的,可能并不适合较小的项目。
  • 复杂性与收益:对于大公司来说,采用复杂技术以获得小的性能提升(例如10%的速度提高)是有意义的,因为他们有足够的资源来管理这种复杂性,并且这种提升可以带来显著的经济效益。然而,对于中小型公司或项目,这种复杂性可能导致不必要的开销和管理负担,而收益却不明显。
  • 资源和资本:大公司通常拥有大量的开发人员和资金,可以支持复杂技术的实施和维护。他们能够通过分工和管理机制来处理高复杂度的系统。
  • 开发者角色:在大公司中,开发者可能被视为大系统中的一个小部分,系统的设计允许快速替换和故障恢复。这种方法在资源丰富的环境中是可行的,但对于资源有限的小团队来说,可能不具备同样的可行性。
  • 管理费用:大公司能够承担因复杂技术带来的管理费用,因为它们的系统规模使得这些费用相对于整体收益是合理的。对于较小的团队,这种管理费用可能会对资源造成不合理的负担。

在选择技术时应考虑项目的实际需求和团队的能力,而不是盲目追随潮流或大公司的技术选择。适合的技术选择应该是根据具体情况量身定制的,以平衡复杂性、成本和收益。

类似“微服务”就是一个很好的反面教材。

3、这项技术在未来5年会变成什么样?

在选择技术时应该考虑该技术在未来4-5年内是否会保持相对稳定。

  • 技术的稳定性:选择一种在未来几年内不会发生剧烈变化的技术,可以降低项目的长期风险。技术的稳定性意味着开发者可以预期其在可预见的未来中不会有重大变化,从而减少频繁的重构和适应成本。
  • 长期支持和维护:如果一种技术已经存在了5年,并且在这段时间内保持稳定或持续发展,通常意味着它拥有一个成熟的生态系统和社区支持。这种技术更有可能在未来继续得到支持和更新。
  • 减少不确定性:新技术往往伴随着不确定性,尤其是它们未来的发展方向和市场接受度。如果一项技术历史较短,其未来的变化和持久性难以预测,这可能会增加项目的风险。
  • 投资回报:在技术选型时,投入学习和实施的成本是一个重要考虑因素。选择相对成熟且稳定的技术,可以确保这些投入在未来几年内仍然有价值,而不需要频繁地转向其他技术。
  • 简化选择过程:通过考虑技术的长期稳定性,可以在技术选型过程中快速排除那些不够成熟或未来发展不确定的选项,从而简化决策过程。

总之,这种评估方法旨在帮助团队做出更为稳健和可持续的技术选择,尤其是在资源有限的情况下,需要确保技术选择能够支持项目的长期发展目标。

很多“JavaScript框架”的半衰期都不到1年!

4、不要仅因为某项技术“酷”或“流行”就盲目采用

  • 情感与理性:选择技术时,应明确区分是因为技术的实用性和解决实际问题的能力,还是因为其新颖性和吸引力。过于依赖情感因素可能导致不必要的复杂性和未来的问题。
  • 理智评估:当你发现自己在为使用某项技术找理由时,可能需要停下来重新评估。这种自我反思可以帮助避免因为一时冲动做出不成熟的决策。
  • 影响者的角色:开发社区中的影响者往往会迅速关注和推广新技术,因为这对他们的职业和影响力有利。然而,他们的动机可能与实际项目的长期需求不一致。他们可能不需要面对长期维护的挑战,也可能有资源在技术不再合适时进行重写。
  • 长期项目的可持续性:对于需要长期维护的项目,选择稳定且可靠的技术至关重要。对于那些需要在几年后对项目进行重写的可能性,需要谨慎考虑。多数情况下,客户或项目方可能不会愿意为因为技术选择不当而导致的重写买单。
  • 经济和实践约束:在项目中引入新技术时,需要考虑到实际的经济约束和长期维护的可行性。确保选择的技术在未来几年内仍然适用,并且不会因为技术潮流的变化而需要额外的投资。

总之,在技术选择中保持理性,开发者在决策过程中以实际需求为导向,而不是被技术的表面吸引力所左右。

5、项目利益高于个人成长

在项目开发中责任感和对项目长期利益的重视。

  • 开发者的选择与责任:开发者在选择技术时,不应只考虑个人的兴趣或学习机会,而应优先考虑项目的需求和可持续性。选择适合项目的技术,而不是单纯因为个人想尝试新技术。
  • 交付时间与项目成本:选择不熟悉或新兴的技术可能会导致开发时间加倍,增加项目成本和延误交付。对于项目和团队来说,使用成熟且团队熟悉的技术通常更有效率。
  • 项目的可维护性:当开发者选择新技术而不是成熟技术时,可能会在离开项目后留下一个难以维护的系统。接手维护的团队可能会面临更陡峭的学习曲线和维护挑战。
  • 个人成长与项目需求的平衡:虽然学习和使用新技术对开发者个人成长有益,但在商业项目中,开发者需要在个人兴趣和项目需求之间找到平衡。
  • 长期视角:开发者应从项目的长期利益出发做出技术决策,而不是只关注短期的个人收益。项目的成功和可持续性应该是首要考虑因素。
  • 总的来说,发者在技术选择中要有责任感和长远眼光,确保技术选择不仅对个人有利,更对项目的成功和长期维护有利。

6、客户需求比技术更重要

在技术选型时强调客户需求的重要性是因为:

  • 专注于业务问题:重点应放在解决实际的业务问题上,而不是追逐技术潮流。技术应该服务于业务目标,而不是为了技术而技术。
  • 满足实际需求:技术的最终目的是解决客户的实际问题和需求。如果技术选型偏离了客户需求,即使技术再先进,也可能无法实现项目的核心目标。
  • 用户体验:客户需求直接影响用户体验。选择能够最佳满足客户需求的技术,可以提高产品的用户友好性和满意度。
  • 成本效益:过于复杂或不必要的技术可能增加开发和维护成本。通过关注客户的实际需求,可以选择最具成本效益的解决方案。
  • 项目成功:项目的成功通常以客户的满意度为衡量标准。技术选择应服务于项目目标和客户期望,以确保项目成功交付。
  • 灵活性和适应性:以客户需求为导向的技术选型可以提高项目的灵活性和适应性,使其更容易随着客户需求的变化而调整。
  • 长期关系:满足客户需求的项目更可能建立长期的客户关系,带来持续的业务机会。

总之,在技术选型中优先考虑客户需求可以确保项目的相关性和成功,提高客户满意度,并优化资源的使用。

最好的决策

最好的技术决策往往是那些在被证明是错误的情况下不会让你陷入困境的决策。

如果您考虑向技术栈中添加新技术,您应该问自己以下五个问题:

  • 我们如何部署它?
  • 我们如何维护它?(几年后这仍然有效吗?)
  • 我们如何训练人们使用它?(我能让新员工在这方面快速提高工作效率吗?)
  • 当失败时我们如何恢复?(如果我意识到这是一个错误的决定,我是否能够及时切换到不同的技术?)
  • 我们如何在本地开发它?

反面例子:计划性报废与硬件绑定

计划性报废是指制造商有意设计产品,使其在一定时间后失效或过时,以促使消费者更换新产品。

计划报废的种类:

  • 系统性计划报废:故意更改系统设计,让产品难以继续使用。例如软件刻意不向下兼容,或是经常更换螺丝规格、刻意让既有工具无法使用。
  • 预先设置的报废:例如有些厂商在喷墨打印机的墨水匣里面加上计数用的芯片,当用户打印了一定的页数或使用了一定的时间之后,即使墨水匣里面还有墨水,墨水匣便停止作用。
  • 软硬件限制:有些软件或程序会故意调整旧硬件,使其性能降低,迫使用户更换新产品。苹果公司曾通过系统更新降低部分iPhone手机的执行速度,却未事先告知用户。
  • 刻意使用易损坏的零件和材料:某些品牌的洗衣机设计有易损部件,如塑料齿轮,这些部件在使用几年后容易损坏,导致整个机器无法使用。
  • 不提供维修零件或增加维修难度:非必要的情况下加胶黏死产品,造成维修拆解会破坏商品。

计划性报废案例

以下是一些广为人知的计划性报废案例,涵盖多个领域,以帮助理解这种现象的广泛性和具体表现:

电子产品

  • 智能手机:
    • 苹果公司(Apple):因软件更新导致老款手机变慢。2017年,苹果承认通过软件降低老旧型号iPhone的性能以避免电池老化问题,引发广泛争议。
    • Android手机:许多安卓手机停止提供系统更新,用户不得不升级设备以获取最新功能或安全补丁。
  • 打印机:
    • 某些品牌(如佳能、惠普)限制打印机墨盒的打印页数,甚至内置计时器,在一定使用时间后停止工作,要求更换墨盒或新设备。
    • 打印机芯片阻止使用第三方兼容墨盒。
  • 电视机:
    • 早期的CRT电视设计为难以维修,后来智能电视可能在软件更新停止后变得无法使用流媒体服务。
  • 笔记本电脑:
    • 电池不可更换的设计(如一些苹果MacBook机型)。
    • 硬件升级受限,例如焊接的RAM和SSD,用户无法自己扩展硬件性能。

家电

  • 洗衣机和冰箱:
    • 某些品牌故意使用低质量的塑料部件(如排水泵)以增加故障率。
    • 电控板设计为不可维修,故障后需要整体更换高昂的零部件。
  • 吸尘器:
    • 使用低质量的过滤器或马达,容易损坏。
    • 电池不可更换,导致设备寿命受限。

汽车

  • 更换零部件的复杂性:
    • 某些汽车制造商定期改变零件规格,使得老款车型维修成本提高。
    • 故意将关键零部件设计为不可单独更换,例如整体式大灯、组合式刹车盘。
  • 软件限制:
    • 某些车型通过限制软件更新,让老款汽车的娱乐系统无法运行新应用(如导航或音乐流媒体)。

软件和技术设备

  • 操作系统与软件:
    • 微软(Microsoft):停止支持旧版本的Windows操作系统(如WindowsXP),让硬件无法运行最新软件。
    • Adobe:订阅模式下停止支持永久许可证版本,迫使用户转向订阅服务。
  • 游戏主机:
    • 游戏厂商停止对旧主机的游戏开发和服务支持(如任天堂Wii、PlayStation3),推动用户购买新型号。
  • 耳机:
    • 某些无线耳机(如AppleAirPods)因电池设计不可更换,使用寿命仅约2-3年。

时尚与服装

  • 快时尚品牌:
    • 快时尚(如Zara、H&M)每季度推出新系列,促使消费者更快淘汰旧衣物。
    • 使用廉价材料,衣物容易磨损或变形。
  • 鞋类:
    • 某些品牌通过在鞋底使用难以修复的材料(如泡沫底)缩短鞋子的使用寿命。

日用消费品

  • 灯泡:
    • 最早的计划性报废案例之一是1924年的**“灯泡卡特尔”**,通过限制白炽灯泡的使用寿命在1000小时以内,增加销售量。
  • 剃须刀:
    • 某些品牌通过更换刀片设计增加长期使用成本。
    • 电动剃须刀电池不可更换,导致整体报废。

交通工具

  • 电动滑板车:
    • 许多共享滑板车内置不可更换的电池或零件,寿命仅约1-2年,之后直接报废。
  • 自行车:
    • 某些品牌使用专有零件(如特殊规格的轮胎或轴承),限制用户自行维修。

其他领域

  • 医疗设备:
    • 某些医用仪器被设计为在使用一定次数后停止工作,甚至无论其实际状况如何都需强制更换。
  • 电子玩具:
    • 内置不可更换的电池,电量耗尽后无法继续使用。
  • 厨房用具:
    • 搅拌机、榨汁机等设备中使用塑料齿轮,易于磨损。
    • 刀片部分无法单独更换,需要整体更换整个组件。

什么是硬件绑定?

硬件绑定是指厂商通过技术手段将设备的某些硬件组件(如屏幕、电池、主板等)与设备唯一标识或加密芯片绑定,使得这些组件只能在官方渠道更换或激活。这种行为在近年来逐渐普及,尤其是在笔记本电脑、智能手机等消费电子产品中。

对用户的影响

  • 维修成本高昂
    • 官方维修通常价格较高,用户需要承担更高的更换费用,尤其是在保修期外的情况下。
    • 相比之下,第三方维修通常更便宜,但硬件绑定限制了用户的选择。
  • 维修不便
    • 用户必须依赖官方维修渠道,可能需要邮寄设备或前往指定维修点,耗费时间和精力。
    • 在某些地区,官方维修点可能较少,进一步增加了维修难度。
  • 用户自主权受限
    • 硬件绑定限制了用户选择维修方式的自由,剥夺了用户对设备的完全控制权。
    • 这种做法被认为是对消费者权益的侵害,尤其是在用户已经拥有设备所有权的情况下。
  • 设备寿命缩短
    • 由于维修成本高或不便,用户可能选择直接更换新设备,而不是维修旧设备。这种行为会缩短设备的使用寿命,增加用户的总体支出。
  • 环境影响
    • 硬件绑定导致的维修困难可能增加电子垃圾,对环境造成负面影响。

硬件绑定行为在保障产品质量和增加厂商收入方面具有一定合理性,但对用户而言却带来了维修成本高、不便和自主权受限等问题。这种行为也引发了计划性报废、环保和法律方面的争议。

硬件绑定案例

电子产品

  • 智能手机专用充电器和配件:苹果公司的 Lightning 接口(直到 iPhone 15 才改为 USB-C)绑定用户使用特定的充电线和配件。一些厂商通过内置芯片的充电器和电缆限制第三方产品使用。
    • 屏幕维修绑定:某些品牌的屏幕更换必须由官方渠道进行,否则可能失去触控功能或出现兼容问题。
  • 笔记本电脑
    • 电池和电源适配器:某些品牌设计不可拆卸的电池,或要求使用特定型号的电源适配器。
    • 配件绑定:MacBook 的 RAM 和存储器焊接在主板上,用户无法自行升级,只能选择购买更高配置的新机型。
  • 打印机
    • 墨盒绑定:许多品牌(如惠普、佳能)设计了带有芯片的墨盒,拒绝兼容第三方墨盒,强迫用户购买官方耗材。
    • 打印纸绑定:专业照片打印机可能只支持特定品牌的打印纸,以保证打印质量。
  • 游戏主机
    • 游戏卡带或光盘:游戏主机(如任天堂 Switch、索尼 PlayStation)限制使用其专用格式的游戏光盘或卡带,拒绝第三方软件。
    • 配件绑定:游戏手柄、VR 设备等通常只能与同品牌主机兼容。

家用电器

  • 咖啡机
    • 胶囊咖啡机:一些品牌(如 Nespresso、Dolce Gusto)设计只能使用特定品牌的咖啡胶囊,不支持其他兼容产品。
  • 吸尘器
    • 专用配件:吸尘器(如戴森)限制用户只能使用官方吸头或过滤器,第三方替代品可能会导致设备性能下降或保修失效。
  • 洗碗机和洗衣机
    • 专用清洁剂:部分品牌推荐或绑定专用清洁剂,使用其他品牌可能影响清洗效果或损害机器。

如何评价计划性报废与硬件绑定?

计划性报废与硬件绑定背离消费者的意愿,制造商在产品设计中隐藏计划性报废的意图,使消费者在不知情的情况下被迫承担更多的经济成本。剥夺了消费者对自己财产的完全支配权,这是对自主性的侵犯。这种现象是过度消费文化的产物,体现了资本对利润最大化的无节制追求。

大数据

IBM提出大数据的经典框架:

  • Volume(数量):数据规模巨大。
  • Variety(多样性):数据类型和来源多样。
  • Value(价值):数据中蕴藏价值,但密度相对较低,需要挖掘。
  • Velocity(速度):数据产生和处理速度快。
  • Veracity(真实性):数据的准确性和可信度。

现实世界的问题:

然而,许多数据团队的误区在于过分关注“速度”、“数量”和“多样性”,而忽视了“真实性”和“价值”。前三者相对容易量化和实现,有大量开源项目可供参考;

而后两者则需要深入理解业务,且“真实性”校验耗时费力,“价值”挖掘的成功率难以保证。此外,组织架构的割裂(懂数据的不懂业务,懂业务的不懂数据)以及技术的快速迭代也分散了人们的注意力,导致本末倒置。

数据越大越好?

人们常常用“日处理数据量”、“总存储量”、“集群节点数”等指标来衡量大数据的价值。然而,如果数据得不到有效利用,这些数字仅仅是“资产负债”,而非真正的价值。

盲目追求数据量是常见的误区。收集数据容易,但剔除噪音、提取关键信息却充满挑战。未经有效处理的数据反而会增加工作量,降低效率。掌握数据并不等同于理解世界运行的规律。我们需要通过统计推断等方法,将数据简化并转化为易于理解和建模的形式,从而揭示数据背后的规律。

小数据的价值

与大数据相比,小数据在某些方面具有独特的优势:

  • 信息密度高:小数据通常是针对特定问题精心挑选的,包含更多有效信息。
  • 针对性强:小数据更专注于解决具体问题,例如通过用户访谈深入了解用户体验。
  • 可解释性强:小数据更易于人工分析和理解,结论更具可解释性。
  • 获取和处理成本低:小数据的获取和处理成本相对较低。

因此,小数据并非价值低下,关键在于根据具体问题选择合适的数据类型和分析方法。

统计推断与数据量

传统统计学强调总体和样本的概念,通过分析样本来推断总体。在大数据时代,我们似乎可以获取所有数据(N=全部),但这是一种误解。即使分析网站流量,我们也只能获取访问过网站的用户数据,而无法了解未访问用户的行为。

此外,“n=1”(只观察一个个体就得出总体结论)也是不可取的。

“大数据”的概念常常让人望而却步,甚至放弃接触真实数据的念头。PC时代,我们通过数据洞悉用户需求;

而大数据时代,我们却常常沉溺于各种报表,反而失去了对数据本身的理解。

报表的危机

报表虽然是常见的数据呈现方式,但也存在诸多问题:

  • 需求泛滥且紧急。
  • 报表之间缺乏逻辑关联。
  • 数据加工缺乏设计。
  • 长期使用率低,造成重复开发和浪费。
  • 信息展示有限,细节容易被掩盖。
  • 开发往往基于易实现性而非实际价值。

因此,我们需要警惕对报表的过度依赖。

我们应该分析多大的数据?

“大”是相对的。当数据的规模对现有技术构成挑战时,才能称之为“大”。因此,“大数据”的定义是动态变化的。当单机无法处理时,就需要采用新的工具和方法,这时就可以称为“大数据”。

报表危机:

  • 报表需求铺天盖地
  • 每次业务都很紧急
  • 报表之间缺少逻辑
  • 数据加工缺少设计
  • 时间久了很少用起
  • 重复开发成为垃圾
  • 用和不用放在那里
  • 增加成本没有意义

与其纠结于数据量的大小,不如关注如何有效地利用数据。Excel可以处理的数据可以称为小数据,百万级以下的数据通常可以使用单机进行分析。

日常分析中,数据量应大于“(数值型特征数量+类别型特征的类别数)*10”,且小于100万,并采用合适的抽样方法(如随机抽样、等距抽样、分层抽样)进行数据提取。

质量和相关性至上

“垃圾进,垃圾出”是数据分析的基本原则。与其追求数据量,不如关注数据的质量和相关性。高质量的数据能够降低噪音干扰、更易于理解和解释,并节约资源和成本。

数据大小不是真正的问题

硬件的进步使得处理大部分数据成为可能。许多企业的数据量远没有想象中那么大。与其担心数据量,不如关注如何有效地使用数据,并选择合适的工具。数据本身也是一种负债,保留数据需要承担成本和风险。

“让数据说话”的误区

“让数据说话”的说法常常被误用。数据本身不会说话,它只是客观的记录。会说话的是人,数据分析需要人的解读和判断。数据可能被误用或曲解,因此,数据的验证至关重要。

你需要认知到的是:忽视因果关系是大数据法则的一种缺陷,而不是特征。忽视因果关系的模型无助于解决现存问题,而只会增加更多问题。数据也不会自己说话,它只能够以一种量化的、无力的方式去描述、再现我们身边的事件。

  • 数据不会说话,会说话的是人。
  • 数据不会撒谎,会撒谎的是人。
  • 真数据未必代表着真相,假数据一定意味着谎言。
  • 数据可以生产结论,结论同样可以生产数据
  • 当一个数据无法验证的时候,它毫无用处。

幂律分布的数据在很多地方都会误导人。

大数据是泡沫吗?

关于大数据是否是泡沫的争论由来已久。

  • 正方观点:概念炒作、应用落地困难、技术门槛高、数据质量问题、安全和隐私风险等。
  • 反方观点:数据驱动决策、提高效率和降低成本、创新产品和服务、科学研究的重要工具等。

与其说大数据是泡沫,不如说对大数据的理解和应用存在泡沫。真正的大数据应用需要明确的业务目标、高质量的数据、强大的数据分析能力和有效的数据治理。

不要被“大数据”的概念所迷惑。我们需要理性看待大数据,关注数据的质量和应用,培养数据分析能力,才能真正发挥数据的价值。

关键问题:

  • 我属于什么级别的玩家?
  • 我是技术驱动、业务驱动还是数据驱动?
  • 我是否清楚大数据应用的局限?
  • 我是否准备好打一场大数据应用持久战?
  • 我是否了解大数据风险与数据偏见?
  • 我是否理解并能贯彻大数据思维?

Unix设计思想

这种思想影响深远。

集思广益的智慧

NIH是英文 Not Invented Here(非此创造)的缩写。在软件开发中即为常见。日常工作中,我们常常遇到项目交接的场景,作为接手项目的开发人员,常常做的是“重构”,重构的最主要原因是不愿意阅读别人写的代码,与其阅读别人代码,不如自己重新实验一遍,即为NIH综合征的表现形式。

NIH综合征的特点就是人们会为了证明自己能够提供更加卓越的解决方案而放弃其他开发人员已经完成的工作。

当一个团队拒绝承认另外一个团队开发的应用程序价值时,当人们宁可自己从头编写程序,而不是使用“现成”代码时,当人们压根不愿意使用其他软件,只因为他们是有别人编写的时候,就是NIH综合征在其中作怪。

艺术是对我的展示,科学是对非我的研究,而哲学则是将我与非我联系在一起。

小即是美

小巧的事物能够已独特有效的方式结合其他小事物。简化软件工程:

  • 小程序易于理解
  • 小程序易于维护
  • 小程序消耗的系统资源较少
  • 小程序容易与其他工具相结合

Less is More

Less is More 这是著名的建筑师米斯·凡德洛说过的一句话,意思是“少即多”这是一种提倡简单,反对过度装饰的设计理念。简单的东西往往带给人们的是更多的享受。

苹果创始人乔布斯一生奉行着极简主义:less is more,少即是多,他的苹果手机就是最好的证明。

相比一直堆 feature、堆复杂度,或许砍掉或简化内容是最好的选项。

让每一个程序只做好一件事

这个小即是美表达的意思一致,只做好一件事,说明足够小。越是大型的系统,这个原则越重要,否则越大就越乱。

单一功能原则

在面向对象编程领域中,单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。

这个术语由罗伯特·C·马丁(Robert Cecil Martin)在他的《敏捷软件开发,原则,模式和实践》一书中的一篇名为〈面向对象设计原则〉的文章中给出。马丁表述该原则是基于的《结构化分析和系统规格》一书中的内聚原则(Cohesion)上。

马丁把功能(职责)定义为:“改变的原因”,并且总结出一个类或者模块应该有且只有一个改变的原因。一个具体的例子就是,想象有一个用于编辑和打印报表的模块。这样的一个模块存在两个改变的原因。第一,报表的内容可以改变(编辑)。第二,报表的格式可以改变(打印)。这两方面的改变会因为完全不同的起因而发生:一个是本质的修改,一个是表面的修改。单一功能原则认为这两方面的问题事实上是两个分离的功能,因此他们应该分离在不同的类或者模块里。把有不同的改变原因的事物耦合在一起的设计是糟糕的。

保持一个类专注于单一功能点上的一个重要的原因是,它会使得类更加的健壮。

快速建立原型的乐趣和好处

学习曲线

学习效果不是一条直线,笔直向前,而往往是曲线前进。也就是说:努力与时间未必成正比,是非线性关系。典型的学习曲线,学习成果随着学习时长增加的变化情况,如下图所示:

缓慢开始区

所谓的缓慢开始区,就是变化不大,观察不出,觉得学习上的投入,没有什么产出。大部分人在“缓慢开始区”放弃。

为什么会缓慢?原因有很多,比如说,没有获取到优质的、合适的学习资源,也可能是阅读质量不高,理解不到位,还可能是没有整合到自身知识体系中。

对于“缓慢开始区”的缓慢,要有清晰的认识,保持信心,坚持到通过进入“加速提高区”的关键转折点。总的来说,身处“缓慢开始区”,我们要遵守的原则就是:“学,就对了;做,就对了。”

高原区

高原区是普通人才与一流人才的区分点。进入加速提高区时,很多人都能体会到成就感,有点欣欣然,但很快就会碰到高原区。因为容易掌握的已经掌握,只留下难啃的骨头,如果没有目标感和系统观,容易骄傲自满,自我感觉良好,于是止步不前。克服高原反应,才能成为人才;能够连续通过多个高原区的人,才能成为一流人才。

软件工程师尤其需要高强度持续不断的学习,软件很难一蹴而就。

为什么软件被称为“软件”

相比硬件,软件可以时刻发布新版本。

人类创造的“三个系统”

第一个系统

  • 在背水一战的情况下,人类创建了“第一个系统”
  • 没有足够的时间将事情做好
  • 单枪匹马或是一小群人开发的

第二个系统

  • 使用“第一个系统”验证过的想法来创建“第二个系统”
  • 由委员会设计的
  • 臃肿而缓慢
  • 被大张旗鼓地誉为伟大的成就

第三个系统

  • 由被“第二个系统”所累的人创建
  • 通常会改变“第二个系统”的名称
  • 最初的概念保持不变并显而易见
  • 结合“第一个系统”和“第二个系统”的最佳特性
  • 设计者有“充裕的时间”将任务做好

“三个系统”理论,在我们的工程实践中,随处可以看到这三个系统的身影。第一个系统通常是刚刚发布上线的新系统,这类系统往往功能精简,但又恰好满足需求,虽然偶尔出些小错,但无伤大雅。因为逻辑精简,所以也易于修改和部署,目前,生活还算美好。

随着业务的发展,逻辑也变得无比的复杂,第一系统正逐渐朝着第二系统的方向演进。而更为糟糕的是,无数Boss本着关心业务的态度,不断挑战,不断进行所谓的迭代改进,第一系统终于不可避免地变成了第二系统,臃肿而缓慢,每次一发布新版本,系统就问题不断。

终于,在某次重大故障发生之后,有人站了出来说,不能再这样下去了,我们优化逻辑,调整架构吧。在砍掉过于复杂却无太大作用的逻辑,优化架构之后,第二系统也得以朝着第三系统的方向继续演进。值得庆幸的是,持续恶化的情况终于得到了遏制,生活又重回美好。但此时,仍需保持警惕,防止重回第二系统。

“三个系统”的理论,告诉了我们一个道理:应当尽早建立第一系统,然后,尽量让系统保持在第二系统和第三系统之间。

可移植性的优先权

最强大的计算机并不是那一款有着较快CPU、最大磁盘或安装了最强大软件的机器,使用最频繁的那台计算机才最为强大。

舍高效率而取可移植性

  • 下一代硬件会跑的更快
  • 不要花太多时间去优化程序
  • 最高效的方法通常不可移植
  • 可移植的软件还减少了用户培训的需求
  • 好的程序永不会小时,而会被移植到新平台

采用文本来存储数据

  • 文本是通用的可转化格式
  • 文本文件易于阅读和编辑

软件的杠杆效应

一个人的精力就只有这么多。如果想取得非凡成就,你就必须放大自己对这个时间的影响力。如果仅凭一己之力,能做的事情只有那么多。关键词是“杠杆”。

想编写大量软件,最好的办法就是借用别人的成果。这里所说的“借用别人的成果”是指将他人的软件模块、程序和配置文件集成到自己的应用程序中。通过制作衍生品,你成倍放大了前任开发人员的努力,将他们的成果发扬光大到新的高度。他们软件变得更有价值,因为它们的身影出现在更多应用程序中。

我们生活在一个最好的时代,同时,我们生活在一个最坏的时代。

说是最好的时代,是因为无论我们面对的是怎么的需求,所处怎样的领域,有太多太多的工具(大多数都是免费的)可供我们挑选,有些甚至理想到无须编写任何代码,只需简单配置即可。软件的杠杆效应使我们受益良多,真可以说是站到了巨人的肩膀上。

同时,也请警惕这个最坏的时代,如果我们仅仅满足于会使用工具,仅仅满足于复制+粘贴的话,那我们也就是个“人肉编码机”,编程技艺也无从提高。有太多现成的软件可以使用了,又何必再费力思考呢,一旦产生了类似的想法,是非常危险的,它会让我们满足于现状,止步不前,而终有一天你会发现自己和一台机器又有什么区别呢。

  • 良好的程序员编写优秀代码,优秀的程序员借用优秀代码
  • 避免NIH综合征
  • 允许他人使用你的代码来发挥软件杠杆效应
  • 将一切自动化
  • 使用shell脚本来提高杠杆效应和可移植性

交互式程序的风险

一旦物体缩小到一定程度,人们就无法掌控它们,人类必须依靠工具来提高正常的身体感官技能。

小型事物与人交互性变差的同时,它们之间的交互性会大大增强。小尺寸赋予了它们极大的灵活性。在很多情况下,它们能轻而易举地整合在一起。

你拥有的小物件越多,操控它们就越难。管理这些小物件就成为一个严重的问题。

CUI与GUI

CUI

CUI代表字符用户界面。它是一种用户界面,用户仅通过键盘与计算机进行交互,并且需要命令来执行任何任务。CUI是GUI的前身,并在大多数早期计算机中使用。大多数计算机使用GUI而不是CUI。它通过允许用户在多个文本行(命令行)中向程序提供命令来工作。CUI的基本实例是MS-DOS和Windows命令提示符。CUI的应用之一是它简化了编程脚本的创建。

优点

  • CUI界面不太吸引人。
  • CUI不提供相同的使用简单性或在一个屏幕上操作各种程序的能力。
  • CUI中没有明显的反馈。在相同的情况下,将需要多个附加命令来确认文件传输操作。
  • 用户必须记住各种命令来操作和管理CUI。
  • 在CUI中,一次只能完成一项任务。
  • CUI仅支持使用键盘。

缺点

  • 与GUI相比,CUI使用的内存更少。
  • 使用成本较低,因为可以使用较低分辨率的屏幕。

GUI

GUI代表图形用户界面。GUI使用户能够与操作系统或应用程序进行交互。它执行算术的快速计算并释放CPU来执行其他任务。它提供按钮、窗口、滚动条、标志性图像、向导和其他图标来方便用户。它为初学者提供了一个用户友好的界面。它易于使用、学习,也减少了认知负担。

优点

  • GUI是一种更易于使用的用户界面。由于数据以符号、表格和图标的形式表示,因此用户可以对选项进行分类和导航。用户只需点击它们即可获取其功能。
  • 使用GUI管理多个作业也很容易。用户可以同时工作和观看多个节目。例如,当电影文件在后台播放时,可以使用网络浏览器浏览互联网。
  • 快捷键的使用是图形用户界面最重要的功能之一。如果您需要执行需要几个操作的工作,快捷键非常有用。

缺点

  • 尽管图形用户界面易于使用,但它们在创建时并不相同。GUI有很多文本解释,需要花费大量时间和精力来创建。程序员必须创建、链接,然后为图像分配特定的功能,这需要很长时间。
  • GUI实现并不像使用它时看起来那么简单。程序员必须注意正确创建函数,以便用户可以更轻松地使用此接口。编码人员的一个错误可能会使他们的所有努力都付诸东流。
  • 由于所有图形表示,它通常比其他界面使用高功率和计算机内存。它不节省资源。结果,它将使用大量的计算机资源。
  • 图形用户界面的设计使开发更加复杂和昂贵。此外,GUI必须与附加硬件链接,这可能会增加总体成本。

CUI和GUI主要区别

  • CUI是一种用户界面,用户仅通过键盘与计算机进行交互,并且需要命令来执行任何任务。相反,GUI允许用户与操作系统或应用程序进行交互。
  • CUI是GUI的前身,用户必须在键盘上键入才能继续CUI。相比之下,GUI使得使用鼠标代替键盘成为可能。
  • DOS,Windows命令提示符是CUI的一个实例,而Windows是GUI的一个示例。
  • GUI比CUI更易于使用。
  • CUI只有文本,相比之下,GUI有图形和其他视觉线索。
  • CUI和GUI是与计算机结合使用的用户界面。

避免强制性的用户界面

  • CUI假定用户是人类
  • CUI命令解析器的规模庞大且难以编写
  • CUI偏好“大即是美”的做法
  • 拥有CUI的程序那一与其他项目相结合
  • CUI没有良好的扩展性
  • CUI无法利用软件的杠杆效应
  • GUI不过是CUI的可视化形式

个人的理解是,程序开发过程中切勿开发不同的后台,而是以接口形式交互数据会更有利。

让每个程序都成为过滤器

  • 人们编写的每一个程序都是过滤器
  • 程序不创建数据,只有人类才会创建数据
  • 计算机将数据从一种形式转换成领一种

十条小准则

  • 允许用户定制环境
  • 尽量使操作系统内核小而轻量化
  • 使用小写字母并尽量简短
  • 保护树木(谨慎使用纸张)
  • 沉默是金(执行正常,不反馈任何信息)
  • 并行思考
  • 各部分之和大于整体(小型组件的排列组合)
  • 寻求90%的解决方案(我们需要故意忽略那些代价昂贵、费时费力或难以执行的项目)
  • 更坏就是更好(更差的事物的生命力反而比那些正确或错误的事物高)
  • 层次化思考

让UNIX只做一件事

UNIX和其他操作系统的哲学

  • 雅达利家用电脑:人体工程的艺术
    • 强调软件如何与人沟通,Unix强调软件与软件之间如何沟通
    • 不给用户留出犯错空间,只提供有限的选择权
    • 现代游戏机的实现方法与雅达利家用电脑的理念相同
  • MS-DOS:七千多万用户选择不会错
    • MS-DOS易于使用,简洁有限的命令语言,详细的帮助和错误消息,在限制用户输入的同时增加系统的输出信息,
    • Unix有一个相当强大的命令语言集,错误信息非常简洁,让人头痛不已。
  • VMS系统:UNIX的对立面
    • 将用户完全屏蔽在系统内各种变幻莫测的情况之外,只给用户提供单一的解决路径。
    • 采用”大即是好”的策略,使用规模宏大的单一化程序来满足众多用户的需求。
    • 人们购买VMS是因为需要完成某项确定的任务
    • 基本信念:用户害怕计算机
    • 让需要条条框框的人们易于使用,而不是编写那些让用户DIY的工具包。

文本

    • 文字内容吸引我们取了解更多信息。
    • 文本是一种用来存储和传播思想的廉价方式。
    • 人们可以高效的对文本进行索引和搜索
    • 通过机器将文本翻译成其他语言的花费并不高
    • 文本可以非常准确的传达思想。
    • 由于数据抽象这个概念,因此文字在处理大量内容时更为高效。

Unix思想的衍生。

  • JAVA:舍高效而取可移植性
  • 面向对象:充分利用软件的杠杆效应
  • 重构:简化再简化
  • 互联网:如果更坏就更好,那么充斥在互联网上的烂网页恰恰证明网络会持续存在
  • 无线通信:廉价、高效、移动的通信
  • Web应用:在网络上实时Unix哲学。