3

再读《架构整洁之道》

 2 years ago
source link: https://blog.csdn.net/orbit/article/details/118993164
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.

再读《架构整洁之道》

吹泡泡的小猫 2021-07-22 10:38:04 23
同时被 2 个专栏收录
2 篇文章 0 订阅

时至今日,软件开发技术中最热闹的领域就是前端开发了,各种 xxxScript 语言,各种前端框架,以至于很长时间都没有再听过“面向对象”这种“古老”的词汇了。作为上了年纪的人,当有人问起什么是软件设计的时候,脑子里本能地就会出现 SRP、OCP、DIP 这样的东西。这些“古董”东西现在还有用吗?函数式编程都没有变量了,面向对象的封装还有学习的必要了吗?现在流行分布式系统,“架构师”们言必称分布式设计,在这种体系中各种抽象和接口设计的原则还用得上吗?

就在 SRP、LSP、OCP、DIP 这些词汇快要从记忆中 fade out 的时候,“Bob 大叔”突然跳出来提了一个“简洁架构”的概念,并写了一本新书《架构整洁之道》来“推销”他的“简洁架构”。这一次,他没有从正面解释什么是软件架构,而是不经意地提到了软件架构就是“用最小的人力成本来满足构建和维护系统的需求”。仔细想想,如今的分布式系统设计方法,无非是为了降低系统维护的成本,而之前面向对象系统的那些设计方法,不也是为了满足这句话吗?用什么瓶子装什么酒,全凭一句话,这“老狐狸”,不是一般的滑头啊。

“我所构建的各种软件系统千差万别,但是软件架构的规则却是相同的”,这是“Bob大叔”对软件设计的理解,也是他写这本书的原因。当然,“老年”读者看完这本书的感觉就是心不慌了,因为你所积累的软件设计的知识和原则,仍然适用,并且在不远的将来,还将继续适用。虽说这本书在内容上没有让人眼前一亮的新观点,但是也基本上涵盖了做软件设计需要考虑的方方面面的内容。这本书给我的感觉就是“睁着眼睛瞎说了很多大实话”,其实想想也容易理解,写这种软件设计内容的书,太深了大多数读者看不懂,太浅了被人质疑水平,一般人还真搞不定这种内容的书。但是头顶“Bob大叔”光环的 Robert C.Martin 能搞定,即使是老生常谈的内容,也能说得读者“心服口服”。

“石器时代的软件开发”衡量软件的价值,主要是从软件实现的功能来考虑的,也就是衡量软件的行为对需求的满足程度(行为价值),再加上健壮性之类的考量来评价软件的价值。但是对于大规模软件开发来说,软件的价值就不仅仅是功能的强弱了,软件的价值还包括软件的架构,也就是软件以何种结构被“设计”出来(架构价值)。很多情况下,软件的架构设计都是重要但是不紧急的事情,在头顶交付倒计时牌子的压力之下,完成功能开发的重要性常常因为紧急而被无限放大,于是架构设计就被“牺牲”了,很多人都明白这个道理,但是在关键时刻却无法站出来与这种“陋习”作斗争。这本书再次对这种行为进行了讽刺:“如果你觉得好的架构成本太高,那你可以试试选择差的架构加上返工重来的成本”。在这本书里,“Bob大叔”明确了“为好的架构而持续 Fight” 就是开发团队的责任,如果团队中有软件架构师职责的人,那就是他的责任。所以软件开发团队不要寄希望于别人大发慈悲允许自己做好的设计,也不要怨天尤人说业务部门的人没有给自己足够的时间做好设计,因为那是你自己的责任。如果软件的架构越来越烂,开发人员再也不要抱怨任何人了,那就是因为你没有 Fight 的结果。听听,多可怕!但是掷地有声,没毛病。开发人员自己都不努力,还有谁会关注软件架构的好坏?不过,“Bob大叔”可不仅仅是说说,在这本书的第 2 部分,他举了几个牺牲设计最终失败的悲惨例子,同时给出了在这些情况下为好的架构而持续 Fight 的方法,具有一定的参考价值。

本书的第 3 部分重温了软件设计的 “SOLID” 原则,看过《重构》这本书,但是还不能完全理解这五个基本原则的同学,在这一部分有机会深化对这几个原则的理解。这部分虽然很短,但是对五个原则有了新的阐述,并且都是具体的例子,结合《重构》这本书一起看,有奇效。

面向对象的软件设计到底是什么,怎么用一句话形容这个行为?很多人只能意会,无法言表,看完这本书,终于知道怎么说了,那就是两个控制:

  • 分离系统中变与不变的内容,对变化的部分进行控制

  • 分析系统中的各种依赖关系(对象、组件),对这些依赖关系进行控制

我们一直念念不忘的“高内聚,低耦合”原则,其实就是为了对依赖关系进行控制,还有“对接口编程,不要对实现编程”的原则,也是为了对变化的部分进行控制。那么,到底怎么进行控制?“Bob大叔”说了,就是“用多态的手段 ... 进行控制”。就是这么简单,那么多“专家”,“大师”们端着,作着,就是不说清楚,于是,“Bob大叔”说了,语言如此直白,你还没有被感动的热泪盈眶吗?

如果说“SOLID”原则太过于关注设计实现的细节,那么本书的第 4 部分和第 5 部分则从更大的维度上关注软件架构的实现方法。第 4 部分介绍了组件的构建原则,分别对组件之间的聚合和耦合两类问题进行了分析,阐述了针对这两个问题的应对策略和原则。组件技术出现的初衷是为了解决软件复用的问题,要想实现组件级别的复用,也有一些原则需要遵守。代码级别的复用需要考虑的是代码的职责尽量单一(SRP 原则),依赖尽量简单(ISP 原则),类似的,SRP 原则应用到组件复用上就是 CCP 原则(共同闭包原则)。这个原则说的就是应该将那些会同时修改,并且是因为相同的目的才会修改的类放在同一个组件中,言外之意就是不相关的东西不要放在一个组件中。这很容易理解,如果因为某个功能需要对代码进行变更,那么这些变更最好体现在一个组件中,而不是同时变更很多个组件。ISP 原则要求不要依赖不需要的东西,组件也一样,CRP 原则(共同复用原则)同样强调“不要强迫一个组件的用户依赖他们不需要的东西”。很显然,组件如果满足 CRP 原则,使用这个组件的用户自然就可以避免依赖他们不需要的东西。

对于组件之间的耦合关系,最常见的就是依赖循环,打破这种循环,DIP 原则依然适用。“Bob大叔”还提出了“稳定依赖原则(SDP)”和“稳定抽象原则(SAP)”。所谓“稳定依赖原则”,就是组件之间的依赖关系必需指向更稳定的方向,通俗地讲,就是一个组件不能依赖一个比它还容易发生变化的组件。那么问题来了,怎样衡量组件的稳定性?“Bob大叔”居然整了一个计算公式来计算组件容易变化的程度:

I=\frac{Fan\_out}{Fan\_in+Fan\_out}

Fan_in 是入向依赖,代表组件外部的类依赖组件内部的类的数量,Fan_out 是出向依赖,代表组件内部的类依赖组件外部的类的数量,I 是不稳定性,范围是 [0,1],I 越大标识这个组件越不稳定。简单理解就是组件对外依赖越多,说明这个组件越不稳定,因为外部的变化更容易影响到它。

SDP 原则都用到数学公式了,SAP 原则自然也不是省油的灯。 SAP 原则描述起来有点抽象:“一个组件的抽象化程度应该与其稳定性保持一致”,通俗地讲,一个组件如果对外依赖太多,不稳定,就不要把自己设计的太抽象。稳定的组件应该是抽象的,这样他的稳定性不会影响可扩展性。不稳定的组件如果早早地定出一堆抽象接口,一旦功能扩展要变更,少不了要修改其中的某些抽象接口。而一旦确定要改接口,会影响所有使用这些接口的组件,更不用说会出现今天改一下,明天又要改一下的糟糕局面。那么怎样衡量一个组件的抽象化程度呢?公式来了:

$$ A=\frac{Na}{Nc} $$

Na 是组件中抽象类和接口的数量之和,Nc 是组件中类的数量(包括抽象类、接口类和普通类),A 是抽象程度。

根据这两个原则得到的 I 和 A 的关系,可以推导出这样一个图,位于 (0, 0) 附近的组件,通常稳定且实现具体(不够抽象),设计不佳,难以扩展。位于(1, 1)附近的组件无限抽象,但是没有被其他组件依赖,常常意味着这些组件包含了大量无用的代码。

 位于主序列线附近的组件,一般被认为是在抽象和变化之间取得比较好的平衡,通常一个大型系统中的组件不可能都做得很完美,如果大部分能贴近这条线就非常不错了。

曾几何时,“软件架构师”成了一个高大上的职业,人人都想成为软件架构师。出去参加技术交流,交换回来一堆名片,title 几乎都是“软件架构师”。现如今,很少再看见这样的 title 了,大部分人的名片上印的都是“高级程序员”,或者是“资深软件工程师”。是软件架构不重要了吗?我看不是,这恰恰是狂热之后的理性回归,“软件架构”重新成为程序员的一个基本属性。在本书的第 5 部分,“Bob大叔”对什么是软件架构又“老调重弹”了一把,说什么“... 软件架构师其实应该是能力强的一群程序员...”,还有“... 软件架构的质量和系统能否正常工作关系不大 ... 真正的麻烦在系统的开发、部署和后续的补充开发中 ...”。这些大实话看看就行了,重要的是后面二十几个章节,从软件设计、开发、部署的方方面面阐述“软件架构”需要考虑的内容和一些可实施的方法。比如,《独立性》一章介绍了独立的重要性和软件解耦的各种模式。再比如,《划分边界》一章介绍了“划分边界”的艺术,决定哪些做,哪些不做,哪些在这里做,哪些在那里做,以及边界的通信方式。这些章节的内容都是软件架构中必需要考虑的各种问题和决策,需要读者们自己去体会了。

正如“Bob 大叔”所言,“我过去 50 年学到的东西主要是什么不应该做”,同样,对于软件架构,我们可以从足够多的“坏”的设计中学会什么不应该做。好的架构可能有争论,因为各有各的好处,但是不好的架构是确定的,不会有争论,毕竟还是有普世价值的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK