3.1. 什么是软件架构

软件架构的定义是很不严谨的,有很多不同的表述,有人还把这些表述分为所谓决策派和组成派什么的。我不准备在这里给读者们引经据典。那是考据者的事,不是工作者的事。我表述我的观点。同时我认为,如果你接受我的观点,用这个观点来重新看原来的那些观点,就会发现他们表达的是同一个事情。

用什么办法可以“定义”一个软件呢?把软件Specification写成什么样才能严格“定义”一个软件呢?在我刚入行的时候,和身边的同事有过很多关于这个问题讨论,当时中国(也许全世界都一样,但当时我的眼界不够,也不知道是不是)的软件水平如此之低。我们在这个问题上是很迷惘的。我们经常纠缠于类似这样的问题: “软件设计文档要写到多细才叫设计好了?”,“软件设计文档是否要列出所有的函数?是否要指明这些函数所有的输入输出?”

现在看来,这个问题其实很简单。什么东西能够严格定义一个软件的行为?当然是源代码啊。对于每个情形软件的状态机应该如何反应,不是只有软件源代码本身才能完整表述吗?理解这一点,你就会发现,严格定义的尽头,就是源代码本身,包括编译这个源代码的脚本。最严谨的设计文档,就是源代码。

既然如此,如果我们要写一个“完美”的设计文档,就应该直接开始写源代码。实际上,现在很多人都是这样的,我们常常都是直接写源代码的。

我有一个同学,他爸爸是美院的教授,他画画的时候,从来不定架子的,画个头,然后补眼睛,把眼睛全部画好了,然后画鼻子……他说他这种画法,被他爸爸批为不走正道。但无论如何,他的画是比我画得好多了,我拿笔对着要画的东西比半天比例,画出来都没有他画的传神。我举这个例子,是要说,你如果罩得住,在不断给代码加细节的时候你就脑子里永远都知道你这个细节在整体上的位置是什么,你根本不需要写设计文档,你写出代码来就好了。

所以,并没有什么必然的如何写设计文档的方法,关键是你的脑子有多清晰。像我,几个电话号码都记不利索的,你让我不要进行设计推演,这是肯定不可能的。对端发过来一个请求,我创建一个会话,对端再发初始化信息,我进入准备态,然后超时,我切换到待机状态……这样的设计逻辑,你让我从代码中理出头绪来,我肯定是做不到的,那我就需要画STD(状态变迁图),推演所有可能的状态变迁,化简状态和Action的数量。这个STD,就是我的“设计”,这种设计同样可以表述在代码中。是写成文档,还是直接变成代码,取决于我(包括我的团队)对这个问题的理解能力有多强,以及代码在这个问题上需要综合表述多少个逻辑。我曾经写过一个驱动,状态机管理本身就是一个子模块,可以直接从数据结构上看到所有的状态以及变迁条件和变迁引起的action,这种情况,代码就可以是设计本身的。

所以,“设计应该做到多细”,这个问题是没有答案的,设计是素描的时候你画的所有辅助线,以及你先画出来的部分,在这个设计过程中,你不断增加细节,这些细节很大部分可能就是代码,他们全部是设计的一部分。

理解了设计意味着什么,你也就理解了构架设计意味着什么。然后你就可以理解克莱门茨在《软件架构编档》中的那个总结了——“架构是架构师眼中的设计”。我们从构架进展到设计,然后进展到代码。它们之间并没有清晰的界限。构架也许一开始就是代码,也许是状态图,也许是4+1视图,并没有固定的方法,这都取决于设计对象和设计本身。它们都是架构师对整个设计过程的预判。

所以,构架是一门无法从学院和教材学习的学问,要装作自己在做架构设计很容易,要让架构设计变成最后的代码才是难点。就好像你叼根烟,皱着眉头对着地图的样子也很像个元帅。但是不是元帅看的是你能否把仗打赢,不是看你叼烟的样子是不是够屌。

我们理解软件构架的这个特点,知道我们能做什么和不能做什么,面对的困难是什么,我们才有可能理解常用的构架工具,比如DFD/AFD,STD,Use Case这样的工具,到底可以解决什么问题,不能解决什么问题。而直接学习这些工具,并不能让你学会软件构架。