25

架构设计原则之我见(一):反思 KISS 原则

 4 years ago
source link: https://www.infoq.cn/article/J8rGQJfs4tNxKfX1DBEp
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

写在前面

在架构设计的领域,人们总结出了很多原则。这些原则的用语大都很简略,容易传播。但是提出这些原则的人往往不会特意告诉你,什么场景下应该用这样的原则,什么场景下不该使用。

用心的人也会发现,在实践中应用这些原则时,好像并不是那么回事,有时反而会带来相反的效果。于是,这些原则便沦为心灵鸡汤,或事后总结时作附会之用。

本文针对这一问题,对部分设计原则展开讨论。期望这些讨论可以抛砖引玉,引发读者自己的独立思考,形成读者自己的判断,不再迷信设计原则。而且,不但对本文中所论及的这些原则要如此,对于其他的原则也应当如此。读者对于本文的内容也应保持同样的态度,以形成自己的独立判断为目的,不要简单的全盘接受、全盘认同,那就失去本文的初衷了。

本文将首先从 KISS 原则出发分析,KISS(Keep It Simple, Stupid)原则翻译成中文,意思是“保持简单、愚蠢”。这是一句没有主语的话,猜想主语是指设计师,并且这个“It”所指的应该是设计师所设计的目标系统。这条原则大意是告诫设计师们,在设计系统时要保持目标系统的“Simple and Stupid”。

针对这个原则详细分析,可以发现它有以下几个问题。

没有明确“Simple and Stupid”的判断原则

怎样才能算是“Simple and Stupid”?这是很让人迷惑的地方。人们在认知一句无主语的话时,会下意识地把这句话的主语映射为自己。所以,一般人看到这个原则,下意识给出的都是自己所认知的“Simple and Stupid”含义,当然,这未必是该原则作者所表达的“Simple and Stupid”含义。

要分析这一点,首先需要明确参与目标系统建设的相关角色。

任何一个请设计师设计并建造的为用户服务系统,最少都会涉及到四方人员:系统拥有者、设计师、实施人员、目标用户。而这四方的形成,是由社会分工导致的:

系统拥有者是最终为整个系统买单的人,也是最终获得系统运营收益的人;用户是系统的服务对象;其他两方都是从系统拥有者身上拆分出来的角色,因为系统拥有者不具备设计师的能力,而设计师又不具备按时实施完成的能力。因此,这四方人员在看到这个原则时,对于什么是“Simple and Stupid”都会有各自的看法。

在目标用户的角度,能让业务运作方便,能够节省时间的系统才是 “Simple and Stupid”。因此,用户会要求实施人员做出让他们使用起来“Simple and Stupid”的产品。而在现实生活中,由于分工已经很细,当目标用户的需求传达到实施人员时,已经过许多不同角色的加工,已经严重失真;同时实施人员实现需求也需要较长的时间,因此,系统实现完成后交付给用户使用时,产 生了巨大的时间差。对需求的误解会形成施工的反复,而反馈时间差导致了对需求的处理不及时,往往导致错过业务的最佳时间窗口。因此,用户总对实施人员的输出不满意,而实施人员则觉得是用户的需求不对,两方总是存在冲突。很明显,用户的“Simple and Stupid”很难得到满足。

在目标系统拥有者的角度,花费最少、产出最高的系统才是“Simple and Stupid”。因此,他关注的是如何能够简单地通过这个系统获利,换一句话说, 就是如何能够简单地给他的用户带来便利,节省目标用户的时间。所以,目标系统拥有者的角度,就是在用户的角度之上,多加了一个成本的考虑:为了做到让用户使用起来简单,他需要花的成本是多少?未来的收益又会是是多少?这是他关心的。相对来说,目标用户并不会关心系统建造的成本,用户关心的只是他们在使用系统时所花的成本。

在设计师的角度,他潜意识里当然也会认为方便自己工作的设计才是 “Simple and Stupid”。因此,他会拿出他自己最熟悉的那一套设计,这个思路所带来的后果就是所谓的“金锤子”(Golden Hammer)。

在实施人员的角度,他潜意识里也会希望方便自己的工作,尽早地完成被分派的任务,这是他所希望的“Simple and Stupid”。因此,实施人员会希望设计师给出的设计方案能方便他们落地实现,因为设计师自身的“Simple and Stupid” 观点会对实施人员的工作难度产生巨大的影响。比如体操教练让一个体操队员来做一个后空翻,这是“Simple and Stupid”。但是让一个没经过体操训练的普通人做一个后空翻,这绝对不“Simple and Stupid”,可能会摔断脖子出人命的。

所以,对于技术水平不同的实施者,他会的或者他能够熟练掌握的技术才是 “Simple and Stupid”。如果一个高水平设计师没有考虑到实施团队的水平,给出他所认为的“Simple and Stupid”方案并勉强推进落地的话,要么实现不了,或者勉强实施出来,最后也会问题不断,甚至引发重大事故。因此,设计师要设计 一个系统的话,必须要结合实施团队的技术水平,做出适合他们的架构设计。如此,对实施团队而言才是“Simple and Stupid”。

从上述的分析来看,“Simple and Stupid”是因人而异的,不同的角色有不同的诉求,并不一致,而且这些诉求都存在于各个参与方的潜意识里,很难识别。于是就会形成这样的结果:实施人员的工作常会受限于设计师的设计,因 为设计师要考虑自身工作的“Simple and Stupid”;同时,实施人员在工作时会和 用户直接打交道,而目标用户则会有业务方的“Simple and Stupid”观点,会对实施人员的工作产生冲击。因此,实施人员被夹在用户和设计师的不同“Simple and Stupid”观点之间而痛苦不堪,甚至长期加班都于事无补。难怪实施人员会对业务恐惧,而对设计师则是又爱又恨:遇到适合他们的设计是“爱”,遇到不合适的设计则“恨”。

可见,让各方都得到“Simple and Stupid”是不可能的,那么哪一个才是设计师想要得到的“Simple and Stupid”呢?

首先,设计师这个角色是从系统拥有者身上拆分出来的,需要考虑系统拥有者的“Simple and Stupid”。

其次,系统是给用户用的,需要考虑目标用户的“Simple and Stupid”。

再次,系统拥有者的“Simple and Stupid”已经包含了用户的“Simple and Stupid”,所以,系统拥有者的“Simple and Stupid”才是真正所需要的“Simple and Stupid”,况且他是系统的出资人,理当得到这个利益。而为实现这个利益,先需要考虑用户的“Simple and Stupid”,整个系统才会有收益,才有做的价值;然后才能考虑实现目标系统所需成本的“Simple and Stupid”。也就是说:设计师和实施人员所认为的“Simple and Stupid”,都不是真正的“Simple and Stupid”。

“Simple”与“Easy”

人们在说“Simple”的时候,往往潜意识里说的是“Easy”,即“容易”。如果把“Simple and Stupid”这句话的主语补全的话,那么“Simple”实际 上指的是用户使用起来“Simple”,而人们潜意识里的“Simple”,指的是自身工作的“Easy”。其实, “Simple”并不等同于“Easy”,要把系统做到“Simple”,往往是最难的,一点都不 “Easy”。同样,实施人员负责构建系统,也是设计师所设计系统的目标用户,要让他们也“Simple”,对设计师的要求更高。

当然,如果系统的目标用户是实施人员或设计师自身时,这种情况属于用户、实施者以及设计者三者合体,这是最好的情况。合体之后,减少了分工对设计的影响,需求也不容易失真,系统反而好设计,比如 Git 的设计师本身也是 Git 的用户。如果一个企业系统的设计者自身也是企业系统的用户,这也能提升系统的设计质量,只不过企业系统的用户往往不懂设计。如果大家都意识到这个问题,未来应当会有所改善。

复杂度在不同分工间会互相影响

系统拥有者、设计师、实施者和目标用户,他们之间的复杂度总是有一个整体平衡的关系:如果要把某一方的工作变简单,其他角色的工作则往往会变得更加困难。

比如一个设计师设计出来一个他自认为“Simple and Stupid”的系统,但最终却往往会提升目标用户的使用难度,或者会提升施工人员的实施难度,或者会提升目标系统拥有者的成本、或降低其收益。许多设计师在给企业设计系统的时候,为了其所坚持的“Simple and Stupid”理念,不断地和业务团队发生冲突, 其实只不过是为了方便自己,用自己更熟悉的设计方案而已。然而这么做很容易降低其用户的使用体验,并且这么继续冲突下去,设计师自身的体验也最终会变得一点也不“Simple and Stupid”。

反之,要得到一个让用户用起来“Simple and Stupid”的系统,或让目标系统拥有者觉得“Simple and Stupid”的系统,则会让设计师的工作变得更加复杂、更困难。要做到这一点,需要设计师突破自身的认知,先站在用户的业务角度去考虑,这是非常难的;还要站在老板的角度,要时刻计算着成本,这更难了。许多人都会吐槽,还不如自己来当老板。

如前所述,用户业务访问的“Simple and Stupid”才是目标,所以要先完成用户业务访问的“Simple and Stupid”,然后考虑到系统拥有者的成本,同时去考虑实施者的“Simple and Stupid”,做到低成本可持续迭代,最后才能考虑设计师自身的“Simple and Stupid”,这才是一个设计师所应考虑的“Simple and Stupid”顺序。往往用户的访问方便了,实施者的工作也会相对变得简单,成本也会更低,因为用户的需求清晰了,会避免走很多的弯路。

可见,设计师的工作没法变简单,其自身工作的“Simple and Stupid”只能放在最后才可以考虑。人们总想成为设计师,但为什么只有极少人才能够做到, 可见其工作的困难程度可见一斑。

所以,每个设计师在思考这个原则的时候,都必须先要明确:设计的目的是要先满足谁的“Simple and Stupid”?是自己还是用户?

设计师不能够为了“Simple and Stupid”而去设计

然而哪怕设计师意识到不能只考虑让自己的工作变简单,也知道需要满足用户的业务场景,可如果设计师以“Simple and Stupid”的态度去理解业务场景,也是不可能因此而真正理解业务的。因为在外行看来,用户在其业务领域内的活动永远是复杂的,绝不简单。设计师会因为追求“Simple and Stupid”而简化业务需求,导致很难理解用户的分工,误解业务的需求。

只有当设计师承认自己是业务的外行,放下自己的任何业务观点,放弃自己所谓的设计原则,放下自己的先入为主,从最简单的业务入手,然后逐渐变成业务领域的内行时,他才能真正从业务视角来观察业务。在这个前提下,他才能对业务生命周期以及用户访问生命周期进行分析,才能根据业务分工的不同、或者根据业务流量压力的不同,进行合理的树状拆分。通过这种方式所形 成的设计,一定是符合业务运行规则的;所形成的不同系统,各自的边界一定是清晰的,一定是内聚的,也因此一定是“Simple and Stupid”。

也就是说,只有设计师放低自己的身段,从业务上去分析、拆分,才能够得到一个内聚的结构,这个结构也才因此而被称为“Simple and Stupid”。所 以,这个“Simple and Stupid”的效果只不过是系统设计符合用户业务内聚的一个副产品,是内聚的一个外在表现,并非设计的目标。可见,“Simple and Stupid” 并不是因为追求“Simple and Stupid”而带来的,反而是追求业务“内聚”的一个结果,不能作为设计时目标。

所以,在设计时,设计师一定要站在目标用户的角度,体验并理解用户的 业务,然后再依照目标用户的实际需求进行设计,并形成内聚的系统,那么最终结果一定会是“Simple and Stupid”的。也就是说,“内聚”原则才是设计时的最高目标。

所以,一旦仅仅以“Simple and Stupid”原则作为设计的最高目标,会很容易失去业务的目标,忽视业务人员的诉求,失去业务的“内聚”,从而导致业务问题复杂化,反而使业务的运转变得更加困难。这么下去,也会使设计师、施工 人员和用户三者之间产生冲突,矛盾激化,因为设计师的工作变简单了,用户和施工人员的工作一定会变得更复杂。

“Simple and Stupid”原则的作用

虽然这个原则不能作为设计目标,倒是可以作为审查设计的一个手段。比如在审查一个系统的时候,一旦所设计的系统对于目标用户访问的拆分不够清晰,且不是树状结构的时候,那么这个系统往往会表现出来耦合的问题,牵一发动全身,对用户或施工人员都不够“Simple and Stupid”。因此,这个原则可以作为架构审查时的一个检查点,用来判断一个设计是否合理,反馈给设计人 员,帮助设计人员发现不合理的设计,进而改进设计。

查阅了一下这个原则的出处,发现其原本是军工行业对设计飞机的一个要求。“Simple and Stupid”原则中所说的“Stupid”本义,是形容修理人员对系统组件修理维护时的简单程度,不需要复杂的工具,直接简单替换即可。其针对的是系统组件的修理维护人员,即用户,不是系统的设计者。为达到这一目的,系统设计者必须要做好内聚,不能存在耦合,他的工作因此反而变得更复杂、 更加困难了。感兴趣的读者,可以去研究一下这个原则的历史背景。

不同系统之间“Simple and Stupid”的互相影响

前面讨论的互相影响还仅局限在系统内部。如扩展到更大的范围,那么不同系统之间的“Simple and Stupid”也是会互相影响的,一个设计师对其系统的 “Simple and Stupid”判断也会扩散到外部,对其他系统产生影响,类似“蝴蝶效应”。

比如硬盘设计师设计一块机械硬盘,根本不会去考虑维修的“Simple and Stupid”,因为机械硬盘的维修成本太高,坏了就直接丢弃,不需维修,所以硬盘设计师的工作相对会容易许多。如果要把机械硬盘设计成维修时可以“Simple and Stupid”,硬盘设计师的工作难度会高上好几个级别,还不一定能够实现出 来,成本也会飙升。

而在设计一个软件系统时,则因为机械硬盘无法维修这一前提,也不会在硬盘维修方面考虑“Simple and Stupid”,因此用户在使用软件系统时,就时刻需要考虑硬盘中数据的备份,增加了用户的使用复杂度。可见,硬盘的设计方便了,用户的使用就复杂了。

为了降低用户的使用复杂度,软件系统需要能够自动应对硬盘失效的情况,因此,这一要求就增加了软件系统设计人员和实施人员的复杂度。如果要进一步降低实施人员的复杂度,但却使得软件设计师的工作复杂度进一步增 加。

通过这个例子也可以发现,相关系统的设计师之间,其工作难易程度也是存在连锁反应的:某个系统的设计师工作简单了,其他相关系统的设计师工作则会变复杂。

在目标系统内部拆分树的范围内来说,子系统之间互相影响主要可以分为两个方向:上层节点的设计,会影响子系统的划分;而子系统的设计,则会影响大系统拆分时的取舍。比如上例中,底层硬盘的设计,直接影响了上层软件的设计。而目标系统的设计,也会影响到与其相连的外部系统,并最终扩散到系统外的整个世界。

所以,一旦形成设计师、施工人员和用户三者的分工,他们各自工作的难易程度会有平衡关系,最终会影响到系统拥有者的难度。而设计师是其中最难的工作,不可能达成“Simple and Stupid”。并且在整个系统的设计中,设计师可以对其他某个角色的工作复杂度作出取舍,但绝不能对自己工作的难易程度作出取舍。哪怕需要取舍,也要放在最后一个来考虑。而设计师对自身工作的取舍,往往都是受限于社会整体技术水平的发展,这个取舍最终也会通过其所设计的系统影响到整个世界。

由此也可以看出,“Simple and Stupid”原则无法适用所有的情况。不去了解一个原则的历史,盲目地直接引用到软件行业来,很容易造成误解,因为每个人都可以拿这个原则来为自己的工作辩解。这个原则其实是告诉我们,只有用户的“Simple and Stupid”才是对的。

“Simple and Stupid”与内聚的关系

也有人说,只要做到内聚、低耦合,不就可以满足“Simple and Stupid”了?是的,内聚的系统一定是“Simple and Stupid”。因此,如果已经做到内聚,就不再需要用“Simple and Stupid”原则来判断,“内聚”才是最核心的设计原则。反之, 做到“Simple and Stupid”的系统,则并不一定是内聚的,比如一个足够简单但是耦合的系统,也可以是“Simple and Stupid”,可以很容易让人掌握,可是它并不内聚。所以,“Simple and Stupid”并不能作为“内聚”的判断标准,也不能作为设 计目标。

而“内聚”才是设计的真正目标,只有“内聚”才是各个行业、各个领域通行 的原则,为什么呢?因为只有内聚才能够保证权责对等,才能保障个体在空间 上的连续与完整,不同个体才得以占有独立的空间,才能符合现实世界的特质!因此,做设计时,不如直接强调“内聚”原则。

为了论证内聚,人们用了很多理论,但“内聚”这个词已经足够好用了,应该担心的反而是人们对“内聚”这个词内涵的正确理解,比如下文中的一些原则也有对“内聚”的不同表述,也很容易令人造成误解。

参考资料

KISS 原则维基百科


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK