3.276. 逻辑的范围问题

3.276.1. 正文

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

我们给出这样一个问题

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

备注

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

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

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

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

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

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

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

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

备注

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

……

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

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

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

所以:

  • 每个设计确实都是可以构成有效的封闭空间的

  • 封闭空间虽然抽象,但它是严密的

  • 封闭空间的严密,在于它只在有限的范围中起作用,所以不谈范围,无所谓设计,更无所谓构架设计。

3.276.2. 后记

3.276.2.1. 补充1

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

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

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

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

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

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

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

3.276.2.2. 补充2

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

备注

软件是一个复杂逻辑的组合,我这个文档强调的就是这一点:你不能指望基于“全知”来做架构设计,因为软件是会升级的。所以,我马上要举的例子,是站在全知的角度让你理解问题,不表示在实际操作的时候你真的可以知道所有的现实。所以前面才有那个用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快这个话题呢?

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

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