怎么判断当前使用的ssh命令是否是OpenSSH的?

要判断当前系统中使用的 ssh 命令是否是 OpenSSH 实现(OpenSSH 是 SSH 协议的最常见开源版本,在 Linux、macOS 等系统默认使用),可以采用以下方法。这些方法基于命令输出或文件检查,适用于大多数 Unix-like 系统(如 Ubuntu、macOS)。如果您使用 Windows,可能需调整为 PowerShell 或检查 PuTTY 等工具。

方法 1: 使用版本检查命令(推荐,最简单)

运行以下命令:

ssh -V

预期输出:

  • 如果是 OpenSSH,会显示类似:

OpenSSH_9.6p1, OpenSSL 3.0.13 30 Jan 2024

开头以 “OpenSSH_” 表示是 OpenSSH 版本(数字如 9.6p1 因系统而异)。

  • 如果不是 OpenSSH(如 Dropbear 或其他实现),输出可能不同,例如:

Dropbear: Dropbear ssh-2024.85

方法 2: 检查命令路径和链接

运行:

which ssh

输出路径如 /usr/bin/ssh(Ubuntu 默认)。

然后检查文件类型:

ls -l /usr/bin/ssh  # 替换为实际路径

如果是符号链接指向 OpenSSH 二进制(如 /usr/bin/ssh -> /usr/sbin/openssh-ssh),则可能是 OpenSSH。

或使用:

file /usr/bin/ssh

输出中包含 “ELF executable” 和架构信息,但不直接确认;结合版本检查使用。

方法 3: 检查安装包(适用于 Ubuntu/Debian 系统)

运行:

dpkg -S $(which ssh)

如果输出包含 “openssh-client” 或类似包名,则是 OpenSSH。

或者:

apt list --installed | grep openssh

看到 “openssh-client” 或 “openssh-server” 表示已安装 OpenSSH。

方法 4: 检查帮助或手册

运行:

ssh --help

OpenSSH 的帮助输出会列出特定选项(如 -V, -vvv),与其他实现(如 lsh 或 Tectia)不同。

常见注意事项

  • 多实现共存:如果系统有多个 SSH(如通过 Homebrew 在 macOS 安装),使用 which ssh 确认当前 PATH 中的是哪个。
  • 如果不是 OpenSSH:可能是 Dropbear(轻量级,用于嵌入式系统)、PuTTY(Windows GUI 工具)或其他商业实现(如 Tectia)。这些通常不支持所有 OpenSSH 选项。
  • 测试连接:运行 ssh -vvv user@host(详细模式),日志中会显示”OpenSSH”,如果是该实现。
  • 如果命令不存在,安装 OpenSSH:Ubuntu 上运行 sudo apt install openssh-client
  • Windows 11企业版自带OpenSSH。

The ~/.ssh/config File: Make Your SSH Life 10× Easier (and Safer)

If you SSH into multiple machines every day and you’re still typing long commands like

ssh -i ~/.ssh/special_key -p 2222 [email protected]

…then you are suffering needlessly.

The ~/.ssh/config file is the single best way to stop that pain. It’s a per-user OpenSSH client configuration file (usually at /home/yourname/.ssh/config or ~/.ssh/config on macOS/Linux), and it lets you centralize all your connection logic so you rarely need flags anymore.

What it actually does (the good parts)
1 Host aliases / nicknames
Turn ugly connection strings into one nice short name.

Host prod-db
    HostName 10.88.12.45
    User admin
    Port 2222
    IdentityFile ~/.ssh/prod_rsa

After that, you just type:

ssh prod-db

2 Common options you almost always want

  • User — default username
  • Port — non-22 ports
  • IdentityFile — which key to offer (and only that key if you pair it with IdentitiesOnly yes)
  • ProxyJump — jump hosts / bastions (the modern replacement for ProxyCommand)

Example with a bastion:

Host internal-server
    HostName 192.168.77.22
    User deploy
    ProxyJump bastion.corp.example.com

3 Wildcards & patterns for groups of hosts
Very powerful once you have 10+ machines with similar setup.

Host *.staging.example.com
    User staging
    IdentityFile ~/.ssh/staging_key
    ServerAliveInterval 30

Host prod-*
    IdentitiesOnly yes
    IdentityFile ~/.ssh/prod_ed25519

4 Security & hardening tricks (things people usually learn the hard way)

Host untrusted-host
    StrictHostKeyChecking accept-new
    UserKnownHostsFile /dev/null     # only for throwaway/testing hosts!

Host *
    # Good defaults everyone should consider
    ServerAliveInterval 60
    ServerAliveCountMax 3
    Compression yes                # sometimes helps a lot on slow links
    ForwardAgent no                # safer default nowadays

Quick example people actually use

# ~/.ssh/config

Host *
    ServerAliveInterval 30
    ServerAliveCountMax 5
    AddKeysToAgent yes
    UseKeychain yes               # macOS only, keeps passphrase in keychain

Host jump
    HostName jump.corp.example.com
    User jumpuser

Host *.internal
    ProxyJump jump
    User app
    IdentityFile ~/.ssh/internal_ed25519

Host laptop
    HostName 192.168.1.88
    User pi
    Port 8822

Important gotchas / pro tips
1 Permissions must be 600: chmod 600 ~/.ssh/config
OpenSSH will silently ignore the file if it’s too permissive — very common source of “why isn’t my config working?” pain.

2 User-level ~/.ssh/config overrides /etc/ssh/ssh_config

3 The file is not shell script — no variables, no conditionals (except the limited Match blocks in newer OpenSSH versions)

4 You can split config into multiple files with Include (OpenSSH ≥7.3):

Include ~/.ssh/config.d/*.conf

Once you start using it properly, going back to flag-heavy SSH feels like using vi without a .vimrc. Highly recommended.

What are your favorite ~/.ssh/config tricks?

~/.ssh/config 文件的作用

~/.ssh/config 文件是 OpenSSH 客户端的配置文件,位于用户主目录下的 .ssh 子目录中(例如 /home/username/.ssh/config)。它允许用户自定义 SSH 连接的行为,而无需每次连接时手动指定选项。该文件的作用主要包括简化 SSH 操作、提升安全性和管理多个主机的连接配置。

主要作用

  • 简化命令:通过定义主机别名(Host),可以将复杂的连接参数封装起来。例如,将一个远程服务器的 IP、端口、用户名等预设为一个短名称,以后只需用 ssh alias 即可连接,而无需输入 ssh -p 2222 [email protected]
  • 自定义连接参数:支持设置各种 SSH 选项,如:

端口(Port):指定非标准端口。

用户名(User):默认登录用户。

密钥文件(IdentityFile):指定私钥路径,避免每次手动加载。

代理跳板(ProxyJump):配置跳板机连接。

其他高级选项:如 KeepAlive、Compression 等,用于优化连接稳定性或性能。

  • 提升安全性:可以限制特定主机的认证方式(如 IdentitiesOnly yes,只使用指定密钥),或禁用不安全的选项(如 StrictHostKeyChecking no,但不推荐)。
  • 主机匹配:支持通配符(如 Host *.example.com),对多个相似主机应用同一配置。

文件格式示例

文件是纯文本,使用键值对格式(不区分大小写)。示例:

Host myserver
    HostName 192.168.1.100
    User myuser
    Port 2222
    IdentityFile ~/.ssh/my_private_key

注意事项

  • 文件权限应为 600(chmod 600 ~/.ssh/config),以确保安全。
  • 如果文件不存在,可以手动创建。
  • 系统级配置在 /etc/ssh/ssh_config,但用户级 ~/.ssh/config 优先级更高。
  • 适用于 ssh、scp、sftp 等命令。

SEO技术之前端技术选型

前端页面使用静态页面(SSG)方式部署,是SEO最友好的。

前端页面使用服务器端渲染(SSR)方式呈现给搜索引擎,SEO次优。

如果你的前端主应用必须是使用Vue.js或React.js等框架开发的单页应用(SPA),但还有其他的营销相关页面 (落地页、关于页、wiki、博客等),请单独部署这些页面!理想情况下,营销页面应该是包含尽可能少js代码的静态HTML,并用静态页面(SSG)方式部署。

奥卡姆剃刀 (Occam’s Razor)又叫简约法则:如无必要,勿增实体

奥卡姆剃刀 (Occam’s Razor):如无必要,勿增实体。——奥卡姆的威廉 (William of Ockham)

奥卡姆剃刀指出,在几种可能的解决方案之中,最有可能的解决方案便是概念和假设最少的那个。因为这个解决方案最为简单,只解决了问题,并且没有引入额外的复杂度和可能的负面后果。

参见:

例子:

也就是说,在多个能够解决同一个问题的方法中,最简单有效的那种方法是最好的。

奥卡姆剃刀(英语:Ockham’s Razor、拉丁语:Lex Parsimoniae,意为“简约法则”)是由14世纪方济会修士奥卡姆的威廉(William of Occam,约1287年至1347年,英格兰萨里郡奥卡姆 (Ockham)人氏)提出的逻辑学法则,他在《箴言书注》2卷15题说“切勿浪费多余功夫去做本可以较少功夫完成之事”。换言之,如果关于同一个问题有许多种理论,每一种都能作出同样准确的预言,那么应该挑选其中使用假定最少的。尽管越复杂的方法通常能做出越好的预言,但是在不考虑预言能力(即结果大致相同)的情况下,假设越少越好。

所罗门诺夫的归纳推理理论是奥卡姆剃刀的数学公式化:在所有能够完美描述已有观测的可计算理论中,较短的可计算理论在估计下一次观测结果的概率时具有较大权重。

在自然科学中,奥卡姆剃刀被作为启发法技巧来使用,更多地作为帮助科学家发展理论模型的工具,而不是在已经发表的理论之间充当裁判角色。在科学方法中,奥卡姆剃刀并没有被当做逻辑上不可辩驳的定理或者科学结论。在科学方法中对简单性的偏好,是基于可证伪性的标准。对于某个现象的所有可接受的解释,都存在无数个可能的、更为复杂的变体:因为你可以把任何解释中的错误归结于特例假设,从而避免该错误的发生。所以,较简单的理论比复杂的理论更好,因为它们更加可检验。

客观剃刀理论

通用图灵机的最小指令集所需要的长度,在不同的形式中是大致相同的,而且其柯氏复杂度比大部分实际的理论小。马库斯·胡特在对剃刀的规范化中,利用这一恒常性定义了“自然”图灵机,用来排除那些过于复杂的指令集。将通用程序的描述作为“假设”,将证据的表示作为“程序数据”,可以在策梅洛-弗兰克尔集合论中证明:“模型的普适概率的对数之和加上模型输入的数据的概率的对数之和应为极小”。可以将它解释为让由两个部分组成符号串达到最短,包括模型的符号和数据的符号,这样我们就得到了最小描述长度定律。

将柯氏复杂性和奥卡姆剃刀的概念结合起来的可能结论之一是,一个理想的数据压缩器也会是一个科学解释/公式的产生器。已经有人尝试将已知的定律从简单性和压缩性的法则中重新推导出来。

对于居尔根·施密德胡贝尔来说,奥卡姆剃刀的恰当数学理论已经存在了,就是所罗门诺夫的归纳推断理论及其扩展。

反剃刀

康德为了对抗奥卡姆剃刀产生的影响,创建了他自己的反剃刀:“存在的多样性不应被粗暴地忽视”。

这么看来,奥卡姆剃刀过于实用主义了。

参考

https://github.com/nusr/hacker-laws-zh

https://en.wikipedia.org/wiki/Occam’s_razor

https://zh.wikipedia.org/wiki/%E5%A5%A5%E5%8D%A1%E5%A7%86%E5%89%83%E5%88%80

Unix哲学 (The Unix Philosophy):软件组件应该很小,并专注于做一件特定的事情

Unix 哲学指软件组件应该很小,并专注于做一件特定的事情。将小而简单以及定义良好的单元组合在一起,而不是使用大而复杂的多用途程序,可以更轻松地构建系统。

像微服务架构这种现代实践可以认为是这种哲学的应用,其中每个服务很小,集中于做一件特定的事情,由简单的构建块组成复杂的行为。

另外,盖尔定律 (Gall’s Law)也说了:一个复杂系统势必是从一个简单系统发展而来的。

Unix哲学是一套基于Unix操作系统顶级开发者们的经验提出的软件开发的准则和哲学。

McIlroy:A Quarter Century of Unix

UNIX 哲学由 Doug McIlroy 在1978年的《Bell System Technical Journal 》中发表。道格拉斯·麦克罗伊是Unix系统上管道机制的发明者,也是Unix文化的缔造者之一。他归纳的Unix哲学如下:程序应该只关注一个目标,并尽可能把它做好。让程序能够互相协同工作。应该让程序处理文本数据流,因为这是一个通用的接口。

更加简化的版本是:做一件事,做好它。虽然只有第三条是特指Unix系统的,但Unix开发者们常常同时强调这三个信条。

Pike:Notes on Programming in C

罗勃·派克在他的《Notes on Programming in C》中提到了以下格言。虽然这些规则是关于程序设计的,但作为Unix哲学丝毫不为过:

  • 规则一:你永远不会知道你的程序会在什么地方耗费时间。程序的瓶颈常常出现在意想不到的地方,因此在你确信找到瓶颈后再动手优化代码吧。过早优化是万恶之源
  • 规则二:测试代码。只有在你详细测试了代码,并且发现一部分代码耗费了绝大部分的运行时间时再对程序作速度优化。
  • 规则三:功能全面的算法(fancy algorithm)在处理小规模问题时效率很低,这是因为算法时间效率中的常量很大,而问题往往规模很小。除非你知道你遇到的常常是复杂的情况,否则就让代码丑陋但是简单而高效吧。(即使问题规模确实很大,也首先尝试第二条规则。)根据问题的规模选择对应算法,例如排序算法,在待排序的元素个数很少(两位数)时,使用冒泡排序算法,在待排序的元素个数很多时,使用快速排序算法
  • 规则四:功能全面的算法比简单的算法更容易产生Bug,更难实现。尽量使用简单的算法和数据结构。
  • 规则五:数据决定一切。如果选择的数据结构能很好的管理数据,算法部分往往不言自明。记住,数据结构,而非算法,才是编程的关键。精心设计的数据结构能达到使用简单算法就解决问题的目的。程序=精心设计的数据结构+尽量简单的算法
  • 规则六:没有第六条规则。

Pike的第一、二条规则重申了高德纳的著名格言:“过早的优化是一切罪恶的根源。” Pike的第三、四条规则被肯·汤普逊改述成:“疑惑不定之时最适合穷举。”事实上,这两条规则也是KISS原则的具体表现。则五在之前Fred Brooks的人月神话中也被提及。Jon Bentley的《Programming Pearls》中也有一章阐述了相同的设计哲学。此规则作为“如果你的数据结构很好,那么控制它的算法就无关痛痒了”的例子常常被简化成“简约地写代码,聪明地用数据”。第六条规则当然只是Pike针对蒙提·派森之小品Bruces sketch的幽默发挥而已了。

Mike Gancarz的《UNIX哲学》

1994年,X窗口系统开发组的成员Mike Gancarz根据他自己的Unix系统经验以及和其他领域使用Unix系统的资深程序员们的讨论结果,写成了The UNIX Philosophy,提出了9条训格之言:

一:小即是美。

二:让程序只做好一件事。

三:尽可能早地创建原型。

四:可移植性比效率更重要。现在应该是“可读性比效率更重要”

五:数据应该保存为文本文件。

六:尽可能地榨取软件的全部价值。

七:使用shell脚本来提高效率和可移植性。

八:避免使用可定制性低下的用户界面。

九:所有程序都是数据的过滤器。输入数据->程序->输出数据

此外还有十条原则则并不为所有人认同,甚至还是争论的焦点(如宏内核和微内核之争):

一:应该允许用户定制操作环境。安卓系统和苹果系统,有自己品牌的手机厂家会选择安卓系统,懂技术的极客也许喜欢安卓系统,普通用户喜欢苹果系统

二:让操作系统核心小而轻。

三:使用小写字母并尽量简短。

四:节约纸张,保护树林。

五:沉默是金。

六:并行地思考。人无法做到并行。在高性能服务器端,Go语言很流行,因为它可以方便地编写并发和(或)并行程序;有些轻量级的场景并不需要并发和(或)并行程序,此时使用Python、JavaScript等语言即可

七:部分加部分大于整体。

八:寻找问题的帕雷托法则。

九:程序随需求而增长(更糟就是更好)。软件是应该随着需求而进化

十:层级地思考。

糟糕的更好

Richard P. Gabriel 提议Unix的一个关键优势是他称作“糟糕的更好”的设计哲学。在“糟糕的更好”的设计风格下,接口和实现的简单性比系统的任何其他属性都更重要,包括准确性、一致性和完整性。Gabriel主张这种设计风格拥有关键的进化优势,尽管他也怀疑一些结果的质量。

参考

https://github.com/nusr/hacker-laws-zh

https://en.wikipedia.org/wiki/Unix_philosophy

https://zh.wikipedia.org/wiki/Unix%E5%93%B2%E5%AD%A6

Spotify 模型 (The Spotify Model):团队围绕功能而非技术进行组织

Spotify 模型是团队和组织结构的一种方法,已被 Spotify 实验室推广开来。在此模型中,团队围绕功能而非技术进行组织。

Spotify 模型还普及了部落、行会以及章节的概念,这些是组织结构的其他组成部分。

参考

https://github.com/nusr/hacker-laws-zh

https://engineering.atspotify.com/2014/03/27/spotify-engineering-culture-part-1

KISS原则 (The KISS Principle):保持简单和直白

KISS 原则指明了如果大多数的系统能够保持简单而非复杂化,那么他们便能够工作在最佳状态。因此,简单性应该是设计时的关键指标,同时也要避免不必要的复杂度。这个短语最初出自 1960 年的美国海军飞机工程师凯利·约翰逊 (Kelly Johnson)。

这一原则的最好例证便是约翰逊给设计工程师一些实用工具的故事。那时的他们正面临着一个挑战,即他们参与设计的喷气式飞机必须能够让普通的机械师在战场上仅仅用这些工具进行维修,因此,“直白”这个词应指的是损坏的事物本身和修复用工具的复杂度两者之间的关系,而非工程师们自身的能力水平。

KISS原则是英语 Keep It Simple, Stupid 的首字母缩略字,是一种归纳过的经验原则。KISS 原则是指在设计当中应当注重简约的原则。总结工程专业人员在设计过程中的经验,大多数系统的设计应保持简洁和单纯,而不掺入非必要的复杂性,这样的系统运作成效会取得最优;因此简单性应该是设计中的关键目标,尽量回避免不必要的复杂性。同时这原则亦有应用在商业书信、设计电脑软件、动画、工程上。

这个首字母缩略词根据报导,是由洛克希德公司的首席工程师凯利约翰逊(U-2 和 SR-71 黑鸟飞机等的设计者)所创造的。虽然长久以来,它一直是被写为“保持简洁,愚蠢”,但约翰逊将其转化成“保持简单愚蠢”(无逗号),而且这种写法仍然被许多作者使用。 词句中最后的 S并没有任何隐涵工程师是愚蠢的含义,而是恰好相反的要求设计是易使人理解的。

说明这个原则最好的实例,是约翰逊向一群设计喷射引擎飞机工程师提供了一些工具,他们所设计的机具,必须可由一名普通机械师只用这些工具修理。 因此,“愚蠢”是指被设计的物品在损坏与修复的关联之间,它们的难易程度。这个缩写词已被美国军方,以及软件开发领域的许多人所使用。

另外相类似的概念也可作 KISS原则的起源。例如“奥卡姆剃刀”,爱因斯坦的“一切尽可能简单”、达芬奇的“简单是最终的复杂性” 、安德鲁·圣艾修伯里的“完美不是当它不能再添加时,它似乎是在它不能被进一步刮除时实现的”。

“复杂”往往意味着“灾难”,“简洁”才是“效率”

参考

https://github.com/nusr/hacker-laws-zh

https://en.wikipedia.org/wiki/KISS_principle

https://zh.wikipedia.org/wiki/KISS%E5%8E%9F%E5%88%99

克努特优化原则:过早优化是万恶之源

克努特优化原则(Knuth’s optimization principle):过早优化是万恶之源。

“过早优化是万恶之源”是软件开发届的一句名言。它来源于Donald Knuth的书《计算机编程艺术》(最早由Tony Hoare提出),以下是引用:

这句关于过早优化的原话来自于20世纪60年代出版的书。那是一个不同的时代,那时大型机和穿孔卡很常见,CPU处理周期很稀缺。所以程序优化得不好,可能会运行很长时间。

过早优化在今天该怎么理解?

今天,大多数开发团队都习惯于不断地量产代码并快速迭代,采用敏捷开发方法。如果软件中存在错误,可以很容易地将修复程序部署到Web服务器上。

现代研发过程中仍然存在过早优化的情绪。过早优化是开发人员应该一直考虑的事情,是在日常工作中应该尽量避免的事情。 防止过早优化在大型机时代适用,今天仍然适用。

一个典型的例子是一家创业公司花费大量时间试图找出如何扩展其软件以满足数百万用户。 这是一个非常值得考虑的问题,但不一定要付诸行动。 在担心处理数百万用户之前,你需要先确保100个用户喜欢并且想要使用你的产品。需要首先验证用户反馈

因此业务模式在反复试错或高速迭代阶段,过多的优化,显得很不划算。身处业务线,经常感到被需求压得喘不过气,其实是因为产品经理会更多的关注用户需求,关注业绩提升。

随着计算机系统性能从MHz,数百MHz到GHz的增加,计算机软件的性能已经不是最重要的问题(落后于其他问题)。今天,有些软件工程师将这个格言扩展到“你永远不应该优化你的代码!”,他们发现,有时候代码怎么写似乎问题都不大。

然而,在许多现代应用程序中发现的臃肿和反应迟钝的问题,迫使软件工程师重新考虑如何将Hoare的话应用于他们的项目。

查尔斯库克(http://www.cookcomputing.com/blog/archives/000084.html)的一篇简短的文章,其中一部分我在下面转载,描述了在Hoare的陈述中的问题:

我一直认为这句话经常导致软件设计师犯严重错误,因为它已经被应用到了不同的问题领域。这句话的完整版是“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.”

我同意这一点。在性能瓶颈明显之前,通常不值得花费大量时间对代码进行细枝末节的优化。但是,在设计软件时,应该从一开始就考虑性能问题。一个好的软件开发人员会自动做到这一点,他们大概知道性能问题会在哪里出现。没有经验的开发人员不会关注这个点,错误地认为在后期进行一些微调可以解决任何性能问题。

Hoare和Knuth真正说的是,软件工程师在担心微观优化(比如一个特定语句消耗多少CPU周期)之前,应该先担心其他问题(比如好的架构设计和这些架构的良好实现)。即微观优化的优先级是很低的,至少低于宏观优化(架构设计)、业务需求分析等。

过早优化的原因

1、过早优化出现在一些相对容易解决的问题上。 例如,有人对应用程序有所了解,但不确定如何开发它,那么他可能花费大量时间考虑他可以处理的不重要的事情,例如徽标设计是否会使系统看起来变得高大上。我以前在国企貌似经常发生这样的事。也许这是因为没有一个能总览全局的架构设计师,导致不太懂技术的领导或者客户钻牛角尖。

2、过早优化是一种“美好的愿景”。 例如,想要开始新的爱好的人,如打羽毛球,可能会花费数小时挑选高级装备并在他们开始训练之前规划未来的行动方案,因为这样做很有趣,而且比实际开始训练更简单!在球馆时不时就能看到,除了球技其它都很专业的“爱好者”。

3、过早优化是由于未能正确对任务进行优先级排序。 例如,正在开发软件的人可能过早地优化事情,不是因为要解决(架构、性能)问题,而是因为他们根本不知道如何制定各个研发阶段的计划,识别出各个阶段应该做的工作。这也很有可能因为团队里没有一个能总览全局的架构设计师。

该怎么做?

前几天QCon的围炉夜话,听毕玄说,“09年之前,阿里的技术团队都处于陪(业务)跑状态”。公司在不同阶段,技术团队的重心会不同。初创阶段更多重视业务,业务稳定(垄断)阶段更重视技术本身。 有经验的管理者会通过职位设置,研发力量投入比例来调节业务与“优化”之间的关系。从组织的角度,是希望大多数同学做好本职工作就能很好的平衡业务与“优化”之间的关系。例如在公司发展的某个阶段,出现了架构师这个角色。

作为研发工作的具体参与者和执行者该怎么做呢?从本质上讲,在确定是否应该优化某些内容时,应该考虑以下几个因素,应该问自己的几个重要问题:

1、为什么要优化?你认为在这个阶段,这种优化是必要的,这意味着它将对你的工作产生显著的、积极的影响,还是你现在仅仅关注它,因为你试图避免处理其他事情?

2、优化的好处是什么?从优化中你能得到什么?

3、优化的成本是多少?为了进行这种优化,你需要花费什么资源?

4、优化可能带来的负面后果是什么?这种优化在将来会给你带来什么样的问题?

5、这种优化有多大可能会过时?你现在正在做的优化工作以后是否有重大意义,或者这种优化是否可能过时?请注意,仅仅因为某些东西稍后可能会过时并不意味着你现在不应该处理它,但是这种情况发生的可能性,它发生之前需要的时间以及你在此期间将获得的好处,都是你决定是否优化应考虑的因素。

6、推迟这种优化有哪些优点和缺点?推迟这个特定的优化有什么坏处吗?或许以后你会获得更多的相关信息,你会更好地处理它?

7、你还能做什么?如果你不把时间和资源花在优化上,你会把它们花在什么上?如果你有其他的事情可以做,你是否从中获益更多?

基于这些标准,可以对必须完成的不同任务进行优先级排序,并找出在哪个阶段应该处理哪些任务,以确保避免过早地进行优化。

但是,每次评估潜在任务时,不必问自己所有这些问题。小任务尤其如此,与使用所有这些标准进行评估相比,简单地完成一个2分钟的小任务可能花费更少的时间和精力。

要意识到这些考虑因素,在必要时至少在某种程度上使用它们来评估任务。任务看起来越大,需要的资源越多,或它将产生的影响越大,你应该越谨慎,应该越多地使用这些标准来评估它。

并非所有优化都为时过早

避免过早优化并不意味着你应该完全避免优化。相反,它只是意味着在决定投入资源优化某些东西之前,应该仔细考虑。

人们经常重复“过早优化是万恶之源”的观点,而没有注意到完整的引用,其中说“我们应该忘记细枝末节的优化。在97%时间,过早的优化是所有邪恶的根源。然而,我们不应该在那个关键的3%中放弃我们的机会”。

这意味着评估情况并决定优化某些东西是完全合理的,即使它处于相对较早的阶段。例如你认为小的修改可以带来显着的好处,或者优化可以解决你工作中遇到的瓶颈,或者不优化可能会导致显着的技术债务。

在关于该主题的原始引用中,说这个概念适用于大约3%的情况,但是有效优化的临界值可能高于或低于这个值。例如,一个具有共识原则是Pareto原理(二八规则),在这种情况下,表明80%的积极成果将来自你20%的工作(多做点优化工作也没问题)。

总的来说,为了避免过早优化,应该首先评估情况,并确定在那个时间点是否需要预期的优化。但是,这种方法不应成为完全避免优化的借口,而应该作为尽可能有效地确定任务优先级的方法。

总结

过早优化是试图为时尚早的阶段提高效率的行为,例如,尽管有更重要的任务需要你去处理,你却在业务的一些琐碎的方面开展工作。

过早优化是有问题的,因为它会导致你浪费资源,气馁,在你没有足够的信息时采取行动,或者陷入次优的行动过程中。

人们过早地优化事物的最常见原因是没有正确地确定任务优先级,或者过早优化对于他们来说相对容易处理,这个优化即使不必要也能接受。

为了避免过早地优化事情,在开始之前,你应该确保问问自己为什么要优化,这样做的成本和好处是什么,这种优化可能带来的负面后果是什么,等待的优点和缺点是什么,以及你还可以做些什么。

记住,这并不意味着你应该完全避免优化,而是应该仔细考虑并评估情况,然后再决定进行某种优化。

边际效应递减,应该把资源用在能使效益最大化的地方。

参考

https://cloud.tencent.com/developer/article/1525574

当时内部的过度设计有两个结果:一些设计根本不可能用上,另一些等到用上的时候,发现当初设计的时候考虑不全,还不能用,正所谓半吊子。

很赞同不要过度设计,能满足现在的需求并且做好应对未来变化的准备就够了。刚开始学习编程的时候也是力求设计完美后再开工,后来发现非常痛苦,过于复杂的设计带来了高额的成本,实际上却很难用到。最近看一本介绍Ruby语言OOP的书,提到一个概念:“不要预测未来”,深以为然。

奥卡姆剃刀原则:如无必要,切勿添加。

原文并非谈需求,就是纯粹谈程序性能优化。

Donald Knuth 1974 年在 ACM Journal 上发表的文章 “Structured Programming with go to Statements” 中写道:

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

简言之,没有量化的性能测试检测到真正的性能问题之前,在代码层面各种炫技式优化,不仅可能提升不了性能,反而更会导致更多 bugs

这条程序开发经验被奉为经典,一方面因为提出之人,另外,确实是“伟大的人生经验”。可以有多方面多层面的解读:

需求版本:先骗到合同,再扩容优化。

敏捷版本:先可用,再迭代。

雷军版本:战术上的勤奋掩盖不了战略上的懒惰。

禅师版本:空杯子里面应该先放大石头,这样能装的更多。

山寨版本:先抄袭,后修改。

创业版本:先上线,后优化。

婚姻版本:先结婚,后恋爱。

总之,他们强调先可用、可行、可赚,然后在了解到真正的问题之后,再做调整和优化

总之,这是典型的贪心算法,尽管并不一定保证最终最优,但能让你浪费最少。

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

字面意思是97%优化是不值得也不应该做的,“过早”的那类优化是指这97%,关键点的优化,也就是剩下的3%仍是绝对必要的,虽然作者并没有直接说“这3%应该尽早做”,但某种程度上“we should not pass up our oppurtunities”大概已经包含了这层意思。作者并不反对优化,而且强调作关键优化的必要性。直白地说,他的意思是:不要浪费时间做那些根本不重要的优化。

很多时候,代码架构的很大部分就是关于如何优化,但把这个部分做对是很有必要的,这是那3%里的情况,并不“过早”,因为系统性能和伸缩性其实主要靠好的架构设计,而不是局部优化。

因为需求会变。

很多时候可能你都不知道需求是什么,原型已经开始架构了。

用户可能也不知道他们的真实需求,很多时候当他们看到原型时,才逐步明确需求。常规领域中,90%以上的优化都产生不了用户可感知的价值,所以不要在早期浪费时间,事后进行剖析和优化就是了。

Make it Work.

Make it Right.

Make it Fast.

不要跳过前面两个直奔第三个!

先第一个版本尽快上线抢占市场再说,大多数没赚到钱的项目都活不过几个月,赚到钱了才有闲情在第2、第3个版本慢慢优化,有钱了还可以请技术大牛来优化。

英文”premature optimization”,我觉得“过早”翻译得不确切,premature实际上不是指一个时间概念,而是指没有充分证据的、未经论证的、盲目的优化。应该叫“盲目优化是万恶之源”。用中国老话就是要“不见兔子不撒鹰”。

什么叫“过早”?这个没说清楚。

我看不同的人有不同定义,这里我说两个最重要的:

1. 优化,一定要有证据,这是最重要的。最明显的证据就是跑分,要想跑分就得先通过测试,否则错误的程序谈跑分没有任何意义。要想通过测试,程序就必须能够正确运行,要想正确运行,程序就必须起码写完能运行。换句话说,“没有足够证据支撑的优化是万恶之源”。 2. 第二个,任何性能上的优化都会损失可读性和可维护性,这是必然的。过早优化就可能需求还没稳定。如果需求大改的话,优化也就废了。如果需求小改,那么优化前的代码肯定比优化后的代码容易改。这应该也是一个因素。

总之应该就是想迭代思维那样,“允许不足,增量弥补”,而不是一锤子买卖,那项目的抗风险能力就很低了。

像生命一样会进化的系统才是最适应环境的系统!不会随着环境的变化而进化的物种都被淘汰了。

1个程序跑1分钟,要不要优化?刚毕业的学生会说:太慢了,要优化。

但如果加上一个条件,这个程序只占据整个流程的1%,其余流程要跑3天,你还会不会优化它?

不同场景,不同需求,不同系统,要具体分析,抓大放小。

就像我小时候穿的衣服,我妈总给我买大一号的,可我的生长速度没那么快,每次都是穿烂了都还大。现在轮到我女儿了,姥姥奶奶再给买衣服,我都是让她们直接买正好的就行。

「过早的优化是万恶之源」这句话是我非常喜欢的一句话。虽然是起源于软件开发领域的一句话,但我发现在工作和生活中,在时间管理中,在恋爱中,都有过早优化的问题,牢记这句话可以解决很多问题,甚至是根本性的问题。简单地说,就是计划赶不上变化

参考

https://www.zhihu.com/question/24282796

怎么理解“premature optimization is the root of all evil”?

个人经验是在web开发中,如果早期不考虑数据库结构,各种数据接口的话,后期的扩展和优化会很难做,这句话是不是放之四海而皆准呢?如果不是这段Donald Knuth的名言该如何理解?

你的经验没错。如果一开始把系统的每个部分都只做到20%的水准,那么后期你会发现80-20规则不成立,根本没有什么瓶颈可以”优化”,你得把每个部分都提升到50%水准再说别的。 问题是Don Knuth不是普通程序员,他的基线可能是80%,而他的优化是从80%提升到95%。而很多人把他的话拿来支持自己只做到20%。

我想,Donald Knuth这里说的是为时过早的优化,而不是指早期的设计,你说的数据库结构,各种接口等等,应该是设计范畴的,Design,而不应该是优化,Optimiziation

再说这一句话,优化往往是针对某一个点,某一个性能瓶颈而进行的,而在早期,这个点根本不存在,或者在后期可能都会发生改变,之前的优化功夫都白费了。

他这里说的是优化,不是你理解的设计。设计当然应该先做,而优化则是后期的工作

参考

https://www.zhihu.com/question/20136075

优化的第一个原则是:不要去动它。优化的第二个原则(只对专家来说)是:还是不要去动它。衡量两次,优化一次。

我们把过早优化定义为以性能的名义使设计和代码更加复杂,更不可读,而我们的这些努力并没有被需要的性能检验证明是恰当的(如实际的测量结果和与性能目标对照),并且因此,按定义,将未经证实的价值加到程序中。时常,不必须的和未经测试的努力优化根本不能使程序更快。

总是记住:让正确的程序更快,比让快速的程序正确要容易太多

所以,缺省情况下,不要集中在让代码更快上,首先把注意力放在使代码尽可能性的清楚和可读上。清楚的代码易于书写正确,易于理解,易于重构—并且易于优化。复杂化,包括优化,总是在稍后引入—并且只在必要的时候

这儿有两个原因为什么频繁的过早优化一点也不能使程序更快:

首先,我们的程序员在估计什么样的代码会快些或慢些,代码中什么地方是瓶颈方面是声名狼籍的差。这些程序员包括我们(这本书的作者),也包括你。考虑:现代的计算机有极其复杂的计算模型,通常包括:管道处理单元在并行的工作,很深的缓存层次,预测执行。指令预测…这些仅仅在CPU芯片的层次。在硬件的基础上,编译器在将代码翻译成机器码时,将会用最好的猜测来利用硬件。唔,在所有的复杂性上,仅仅是你的猜测。所以,你如果仅仅是猜测,只有很小的机会才能使你在病态的目标上的微调有显著的提高。所以,测量在优化之前,优化的目标在测量之前。你的注意力应该在优先级为#1的条目 — 为人写代码,直到证明必须优化。(当有人请你优化的时候,请他出示证据)。

第二,在现代的程序中,许多日益增加的操作并不在CPU的范畴内。它们也许属于内存的范畴,网络的范畴,硬盘的范畴,正在等待WEB服务,或者正在等待数据库。在这样的操作中调整应用程序的代码最多只是等得更快。这也意味着程序员总是浪费宝贵的时间在改进那些不需要改进的代码,而没有通过所做的改进增加价值。

当然,确实需要优化某些代码的那天终会到来。当你这样做的时候,请首先看能不能做算法优化(条款7),并试着封装和模块化优化(举例来说,将优化包装在函数或者类中,条款5和条款11),同时在注释中清楚地说明优化的原因和所参考的算法。

一个初学者通常的错误是自负的写新代码,以牺牲代码的可理解性为代价换来执行速度的优化。通常,这产生出一大堆糟糕的代码,即使一开始是正确的,也是难于阅读和更改的。

KISSKeep It  Simple Software保持简单的软件)原则:正确优于快速,简单优于复杂,清楚优于机灵,安全优于危险

即,计算机软硬件系统是一个复杂系统,不是说你想当然地、拍脑门地优化了某段代码后,整个系统的性能就突然提高了,应该在性能测试之后,再针对热点进行优化。

参考

http://coder.zoomquiet.top/data/20120222104457/index.html

过早优化对大的问题在于:

  • 过早关注不重要的部分,而忽略行动和目标本身。
  • 以静态的思维来优化,殊不知,事务发展总是动态的,“优化”是需要长期的实践积累才可以获得。
  • 出发点是好的,但往往好心办坏事,折腾大量的时间,做了很多不该做的,而该做的、重要的反而没做。
  • 强化外部条件、工具等外在,而忽略内在因素和行动本身,或者,过多期望将来,而忽略当下眼前。

活在当下,实实在在做好手头的事,是避免“过早优化”最好的方法之一。

参考

https://www.sohu.com/a/126020757_467792

https://xie.infoq.cn/article/907ae5847c83554de8504c1db