仓库源文

.. Kenneth Lee 版权所有 2021

:Authors: Kenneth Lee :Version: 1.1 :Date: 2021-10-17 :Status: Released

逻辑的范围问题


正文

今天和人讨论到一个问题,我觉得这个例子特别典型,我希望用它来增强我对于 :doc:逻辑闭包 的概念空间的定义。

我们给出这样一个问题

    | memset()和memset_s()谁的性能更高?

.. note::

解释一下:在微软的安全编程库概念中,memset_s是memset的“安全版本”,会检查目标 空间的大小避免内存越界访问。这个概念被用于了更多的其他方案,我们这里指使用类似 方案的所有情形。

也许我们可以给出这个答案:

    | 在90%的情形下,memset性能比memset_s高。

如果你问我,这个结论对不对。我给你的答案是:我一点都不关心。就算这个论断是对的 ,如果我所面对的代码就在这10%的范围内,对我来说,memset的性能100%比memset_s差, 讨论这个问题毫无意义。

对于架构师来说,不构成决策的任何statement,我们都不关心。判断一个东西对不对,要 付出成本的,而且,这个东西怎么用,决定了它对不对,没有给定目标前,无法定义这句 话的范围,所以,这个问题我“不关心”。

好了,现在我们走一步,我们建立一个“逻辑闭包”进行技术决策,我们封闭我们的范围, 我们给出这个论断(Proposition):

    | 由于90%的情形下,memset的性能比memset_s高,所以为了保证本公司测试效率,
    | 在测试环境中,要求不得使用memset_s,必须使用memset。

好了,你给出决策了,我可就有话说了。这里你构造了一个封闭的逻辑空间,给定了范围: 在本公司的的范围内,为了提高测试(运行)效率,用memset代替memset_s。

.. note::

论断中没有说是运行效率,但我这里的理解根据上下文特意理解为“运行”效率,是为了 强调:我们是讨论沟通双方的“意图”,不是抓对方的话柄。

我强调这一点,是因为我们讨论逻辑漏洞的时候会抠得很细,会造成一种好像在 “抓话柄”的假象,但这种细节的区分不是为了争辩本身的输赢,不是为了口舌之利,而 是为了作出正确的判断,从而正确指导我们最终的实践。

我们要挑战一个逻辑链,要不挑战它的证据,要不挑战它的论证。在这里,如果我挑战证 据,我可以这样反驳:我不认90%这个参数,我认为本公司的情形比较特殊,我们用了某种 特殊的处理器,大部分时候memset_s的性能和memset的性能是一样的。或者我们用的编译 器很特殊,无论你写的时候是memset还是memset_s,其实实现起来都会转化成同一种,而 外做这个工作没有意义。这是一种争法。

我们也挑战论证过程:你说这样能提高测试性能,问题是memset占整个测试程序的百分几 ?为什么要给这个强约束给整个公司的项目?为什么不是让每个项目自己判断?你这个约 束的收益在什么地方?

请注意了,如果我选择第二个方法对论断进行挑战,我仍不需要判断90%这个参数对不对, 因为它对不对都不影响我们不能选择这个方案。

架构设计构造的自由度,固定性,都在于我们如何选择我们逻辑证据的位置,坚实的依赖, 可以避免我们的整个逻辑大厦建立在可变的基础上。比如说,要不我们换这个证据基础:

    | 国标要求,所有包含memset的库,必须替换成memset_s的实现,
    | 我们销售的目标市场90%必须符合国标要求,而且5年内不太可能改变。
    | 所以,我们全部使用memset_s的库,删除memset的库。

你看,这我们完全不用管什么性能问题了,这个条件极硬,你最多讨论“不需要满足国标要 求的产品”如何做,其他地方,你找不到任何缝去跳过这个逻辑。

这就是“抓住主要矛盾和矛盾的主要方面”的原理。

所以,我们为什么要独立建一个个的逻辑模型,让它们构成一个个独立的逻辑空间?为什 么我们要单独对逻辑视图,开发视图,运行视图……独立建模?因为我们需要把相关的逻辑 要素封闭在一个我们可以作出理性决策的概念空间中,我们才可以在这个有限的空间里, 反复挑选我们的依赖条件,让这个最坚实的逻辑,成为所有其他逻辑的控制要素,而不是 被总在变的逻辑带偏了我们路线,或者让我们的战略决策变成无目标的热运动。

只有我们从不同角度挖出每个目标的逻辑漏洞,从而把它填上。这样这个决策才是可以落 地的,目标才是可以达成的,而不是口花花说说而已的。

上面这个例子也可以反过来说,比如我们可能会这样论断:

    | 根据某某研究机构的研究结果,在某某应用上使用安全函数后,性能只下降1%,
    | 但安全漏洞减少10%,为此,在本公司推行安全函数编程,以期达成一样的结
    | 果。

这又是一个封闭的逻辑空间,我们就这个问题来挑战它的漏洞,比如:“什么叫‘推行’”, 是建议用,还是把所有产品中的相关函数删除?这个语义确切指什么?

那个研究机构的研究结果范围是什么,和我们的情形是否有可对比性?如果通过重构实现 替换,重构本身引入的安全漏洞有多少?

如果这个研究机构之研究了一个特性的项目,只实施在一个特定的项目上,获得那样的结 果,现在把这个策略推广到我们100个项目上,付出的成本是否可控?

……

这些都是架构设计决策的成本。你不能来个XXX研究结构有个结果,什么范围都不看,结果 的有效范围也不看,就决定在一个很大的范围中判断那个逻辑也成立,并且就决定实施。 这就不是设计,这是街边闲人侃大山呢。

好,假定我们也进行了调查,判断有90个项目没有技术风险(很难,但我们先这样假设), 那么,剩下那10个项目是不在范围中,还是承担这个风险?如果我们决定承担这个风险, 这个(承担风险的)决策我们就需要写在我们的架构设计定义中。

这就是为什么我总说架构设计必然是很脏的,因为高层决策一刀砍下去,能有八成好事就 谢天谢地了,剩下的必然是很难看的,我们很多工作都是去补这个难看的部分。但如果你 压根儿就不提这事,这种架构设计必然是看着好看,其实到处都是洞。(其实这根本就不 是设计,而是耍嘴皮子)。

所以:

后记

补充1

我完成这个建模后,发给讨论的另一方,他给我的反馈是这样的:

    | 拿一个很简单的例子,不让用memset,大部分人只会改用memset_s,这就是
    | 拉低上限的事情。因为编译器对两者产生的代码的优化程度非常不同。导致
    | 的直接结果就是性能会变低。

这种回答在我和别人讨论问题的时候经常发生,也是很个非常典型的设计逻辑不封闭的例 子。所以我进一步讨论这个问题。

这个反馈的论断,背后隐含了一个逻辑:“memset一定比memset_s快”。如果你这一点也看 不出来,那我们就不用讨论了。

而我前面的逻辑链并不反对:“在大部分情形下,memset确实比memset_s快”,我用的证据 是:memset比memset_s慢的情形存在。只要有1%的可能性存在,我的整个证据都是成立的: 因为如果你处于这个1%的可能性范围内,我们的结论就是100%。

除非,你的逻辑链是建立在90%的可能性这个条件上。那这个问题我们另谈。

这就是我想反复强调的架构设计中,逻辑闭包的“严密性”,因为你如何用你的证据,改变 你的结论。如果我们思考战略问题的时候,逻辑链不具有严密性,我们的推演结果可能就 是反的。而我们很多人并不在乎这一点,这让构架设计变成了玄学。你说两嘴,我说两嘴, 最后行不行,和这个架构设计毛关系没有。

补充2

我发现很多人从软件的逻辑的角度,就是认为memset比memset_s快是百分百的。这实在让 我有一种和刚学会写程序的人讨论问题的感觉。但这种情况居然很普遍,我就给一个 reasonable的例子来说明一下吧。

.. note::

软件是一个复杂逻辑的组合,我这个文档强调的就是这一点:你不能指望基于“全知”来 做架构设计,因为软件是会升级的。所以,我马上要举的例子,是站在全知的角度让你 理解问题,不表示在实际操作的时候你真的可以知道所有的现实。所以前面才有那个用 memset比memset_s快的稳固程度不如我们要过国标这个证据的稳固程度的比喻。架构是 挑证据的,不是一个代码某个时刻的snapshot那样,所有证据都在纸面上的。

人们认为memset比memset_s快,是因为在逻辑上,memset做一件事:把某片内存全部设置 成一个值,memset_s需要做两件事:检查要求设置的范围是否越界,把某片内存全部设置 成一个值。这是软件语义,在这个语义上,当然可以认为memset比memset_s快。

但这不是硬件语义,让我们设想一个CPU,在这个CPU中,memset_s是一个硬件行为,我们 不经过store指令一个个把参数设置到内存上,而是直接用一条同步指令memset_s完成这个 功能。但它并没有memset这条指令。所以,如果你调用memset_s,给定了目标的范围,你 要做的就是一件事:按要求给定memset_s的参数,然后调用这条指令。但如果你要做 memset,你要不自己一个个做store,要不先修改系统的引擎参数,disable目标长度这个 全局参数,然后再调用memset_s,然后再恢复这个参数……你看,这样一组合,memset_s才 是一个动作,而memset是多个动作。

如果你仍辩解:这种情况不常见!

拜托,你已经修改你的论断了,那就请您收回前面那个100%的论断,我们站在90%这个可能 性上讨论问题。

所以,很多人觉得自己有能力讨论架构设计,写的那些模棱两可的话语是一种架构设计。 那你其实就没有入门。站在这种思路上讨论问题,跟我说什么“我们的观点本质是一致”的 ,这种话语只是在套近乎,这种高度抽象的语义,在架构设计上几乎没有意义。

这个问题还可以引申一下:为什么人们这么在乎要和我纠缠这个memset的速度一定比 memset_s快这个话题呢?

我觉得,他们实在是太想用这个结论了。如果这个事情能确定下来,我们后面的决策就简 单了。所以,很多人理解不了架构设计。是因为他们很不习惯这种思维方式:架构设计的 建模是反复进行建立,推翻,重建,再推翻,再重建……这样的一个过程。而习惯一般(简 单)编程的人其实更习惯一点点加逻辑这样一个过程,如果中间有一个地方过不去,他们 用一切手段都是希望突破这个点。这在战略决定后不见得是坏事,因为战略决定以后,我 们不能轻易变更。但在做战略这件事情本身上抱这样的执念,就很容易让我们脱离对实际 的判断了。

架构是决定方向,细节才是开始补东西。这是两个不同的判断模型。 。