故善战者,能为不可胜,不能使敌之必可胜。故曰:胜可知而不可为。
——孙武 《孙子兵法》
我们都知道武功包括招式和心法,二者缺一不可。如果只知招式而不知心法,则招式全无用处。某些特殊情况下可能打出来的是打狗棍法的招式,暗地里却是在运用全真剑法的心法,这时本质上其实是在使用全真剑法。甚至有的武功,相同的招式却有两套心法,应该使用哪一套要视情况而定,如果用错了心法,不但不能克敌制胜,反而会死得比不会武功的人还惨!
对于建模这门武功来说,其招式比较简单,无论是UML图、ER图还是数据流图,顶多个把月就能学会;然而它的心法却非常高深繁复,要想融会贯通并能根据实际情况运用自如并不容易。基本功法,是要理解什么是模型以及为什么要建模。
什么是模型
模型是对理论、系统或某个东西的有意识的简化,只关注它们的主要对象或运作方式。模型可以有多种表现方式,它可以是一个仿制品(例如建筑的沙盘模型)、某种表示法(就像我们在中学物理课上学习受力分析时使用的“一个方框代表物体,一个单向箭头代表受力方向”这种规定)、文字描述、二维或三维的示意图以及其它任何方便的表达方法。这里有3个要点:
1) 模型所表现的对象,可以是某个东西,最常见的是建筑物、汽车、机械等等;可以是一个系统,例如人体系统、一个城市、一个企业、生态环境、一个动物族群、一个应用程序等等;可以是一个理论,例如相对论、进化论、牛顿第二定律等等。
2) 模型是对研究对象的有意识的简化,以便把注意力集中在我们关心的主要对象或运作方式上,并且(更重要的)只有把无关的属性去掉,才有可能发现可再现的规律(以便对未来的观测结果作出预测,这也是科学研究的主要目的)。例如牛顿第二定律把物体简化为一个质点(只关心物体的质量这一个属性),把空间简化为平坦的三维空间,把时间简化为不依赖物体的速度和质量的绝对时间。
3) 模型只存在于我们的脑中,不再具有任何其它(不管在任何意义上)的实在性。模型存在的价值只是服务于某个理论,或者表现某个东西或某个系统的一些我们感兴趣的方面。相对论和牛顿第二定律里面的时空模型有很大的不同,不能说这两个模型哪个更接近于“真实”,它们只是各自适合不同的理论。
建模是必须的么?
什么简化啦、抽象啦、概念啦……听到这些故弄玄虚的词儿就让人头大不已。我们(特别是老板^_^)多么希望今天跟客户签了合同,明天,程序员双手结印,大喝一声:“啊咪哞咪吽——我是小强——芝麻开门不要钱——”,小宇宙以及查克拉大爆发,然后喀嚓一下子程序奇迹般地就完成了。这个美好的愿望能够实现么?要回答这个问题,就要先来看看什么是程序。
程序,是一个系统,它具有一个内部状态并存在于一个外部环境中,外部环境也有一个状态。这两个状态总是唯一地决定了下一个内部状态。这个定义里没有包含结构和行为,我们可以简单地认为状态的某些方面可以经验性地证明是持久的、延续的、不变的,这个稳定的部分为系统的结构,而变化的部分则是行为。可以举一个简单的例子,如果我在QQ上对老婆说“我爱你”,我可以预测老婆大人要么收到“我爱你”这三个字,要么啥也收不到,但是绝不会收到“我讨厌你”。我为什么能够预测出老婆可以收到“我爱你”这三个字呢?因为我就是知道——通过连续观察系统的若干次状态改变(譬如我发出“我爱你”老婆收到“我爱你”、我发出“我恨你”老婆收到“我恨你”、我发出“我讨厌你”老婆收到“我讨厌你”),我推断出QQ系统的规律我发出啥老婆收到啥。外部环境的状态,除了我(所输入的字)之外,还包括网络和老婆的电脑,如果网络中断则老婆啥也收不到,如果老婆的电脑里没装中文字体则会收到一堆乱码。值得注意的是,所谓状态是指如果重现则可以由观察者再次识别的情形。如果我在观察QQ系统的状态变化时加上(老婆收到的信息被储存的)内存地址这一属性,则系统的状态变化就毫无规律可言,我也无法根据系统当前状态和外部环境的状态预测系统的下一状态。事实上,我忽略掉太多东西了,对于系统内部状态,我忽略掉了老婆收到信息的存储地址、信息显示的字体大小等等;对于外部环境的状态,老婆是男是女、心情如何,天气是阴是晴、是白天还是黑夜也没有包括在模型之中。是的,任何对系统的理解都少不了一个模型,即使我们没有把它画出来,甚至没有意识到它的存在。
那么把模型画出来又有哪些好处呢?首先,制作模型是一个强迫思考的过程,这和写文章是一个强迫思考的过程一样,园子里的朋友应该都有体会。第二,模型是个很好的思考工具。因为人脑的思考能力非常有限,能同时记住和思考的对象不超过7个,所以边想变画,修修改改,要比只在脑子里面默想要有效得多。第三,模型是个有效的沟通工具,有助于消除程序员之间、程序员与领域专家之间的误解。这一点受到的质疑比较多,有人说UML图这东西很多程序员都看不懂用户又怎么能看得懂呢?这确实是个棘手的问题,一种方法是教领域专家看UML图,当然这要求领域专家够聪明、爱学习、有时间、感兴趣。否则就只有选取或自己发明个领域专家看得懂、感兴趣的沟通工具。一般来说信息系统的用户都是Excel高手,口头交流、草图、示例数据都是不错的招式。
不完全与过于完全
物理研究上的所有成功,都依赖于对观察对象的明智选择。这种选择,一方面是根据对象的重要程度,另一方面则是根据我们对对象特征的主观提取。有些特征尽管颇具吸引力,但当前的科学还无力处理,就只好暂时舍弃。
——詹姆斯·C.麦克斯韦(James C. Maxwell)
玄之又玄,众眇之门。
——老子 《道德经》
操笑曰:“袁绍色厉胆薄,好谋无断;干大事而惜身,见小利而忘命。非英雄也。”
——罗贯中 《三国演义》
如前所述,反映系统所有细节的模型没有意义。模型到底要包括系统的那些属性,一方面是根据属性的重要程度,另一方面则是一种主观提取。“玄之又玄,众眇之门”并不能作为“道”的模型。“极其玄妙深远”这种空洞的形容除了增加我们对“道”的敬畏和向往之外,实在没有更多用处。同样,沙盘模型只关注建筑物的外观,除了糊弄一下投资人和购房者,并没有太大功用。作为袁绍的模型,“色厉胆薄,好谋无断;干大事而惜身,见小利而忘命”同样十分简单,但是可以根据它预测袁绍的行为,所以它是一个好的模型。根据这个模型,曹操做出了很多重要决策,最终在官渡之战以少胜多,大败袁绍。
一个模型就是一种理解
模型是主观的。这一结论也许会让许多人觉得失落,因为这意味着并不存在唯一正确的或者真实的模型。模型既不神秘高深,也不是什么额外的东西,它只是人类理解世界、表达世界的工具。
作为仿真的程序
如果观察一下我们身边形形色色的应用程序,可以发现它们大多被用来仿真现实世界,其目的是节约成本。在反恐精英这款游戏里,玩家手持各种流行的枪械进行一场5对5的搏杀,只需十几分钟的时间。计算机辅助设计、模拟制造技术早已被广泛用于机械制造、航空航天甚至仿真鸟巢体育馆的钢架结构,节约的成本数以亿计。使用信息系统来仿真企业的实际业务,也是希望以更低的成本、更高的效率完成信息的流动、共享、存储、处理和检索。
一个仿真就是对现实世界的一种理解
我曾幻想将来可以出现这样的游戏:它可以完全仿真现实世界里的所有细节。人们进入这个游戏,就如同进入了另一个真实的世界。所以这个游戏不需要人为设计任何情节和角色。对,这个游戏就和《骇客帝国》里面的“矩阵”系统一样。
这样的游戏有可能被开发出来么?正如我们已经知道的,如果我们关注现实世界里的所有细节,我们就无法得到任何可重现的状态。同样,如果游戏仿真了现实世界的所有细节,则我们也无法得到游戏的任何可重现的状态。那么,我们将永远也无法证明游戏真的完全仿真了现实世界。
就像我们接下来将要看到的,由于我们自身所具有的局限性,无论白箱还是黑箱,都无法做到完全的展现。即使这个系统是我们自己构造的也同样如此。
火星人 VS 1-2-3
我想告诉你,火星人想要入侵地球。他们的飞船已经在近地轨道上飞行了三万六千八百八十八圈。他们的目的并不是要毁灭地球,而是要把地球作为他们的殖民地。而且,通过观察,他们发现地球上有一个东西对人类有很强的控制力。火星人相信,只要完成对这个东西的仿真,就可以轻易地奴役人类了。这个东西就是——交通信号灯,俗称红绿灯,当然火星人并不这么叫它,不过为了叙述的方便,我们还是统一叫它红绿灯吧。
可是火星人真的要抓狂了。他们不知道红绿灯到底是如何控制人类的。要搞明白这个问题,他们需要做4项工作:1)确定系统边界:应该把1个灯泡还是2个灯泡还是3个灯泡作为一个系统来研究?或者应该把一个交通岗的4组红绿灯作为一个系统?要不要把行人和汽车包括在系统之中?2)选取系统的一些属性作为研究对象。3)作大量的观测,归纳系统状态变化的规律。4)如果找不到规律,或者觉得找到的规律没啥用,则要重新选取系统边界和研究对象,也就是重复1)、2)和3)的工作,直到找到满意的规律为止。这是个漫长的过程,不知何时才能有所突破,然而火星人的时间已经不多了——他们的领导决定把入侵地球的里程碑定在月底。于是,火星人准备找个领域专家来问问,而这个不幸被选中的人就是我。
火星人:“你懂红绿灯?”
1-2-3:“我当然懂。”
火星人:“给我讲讲。”
1-2-3:“讲什么?”
火星人:“我想仿真一个红绿灯,然后用它来控制人类。告诉我红绿灯是怎么控制人类的。”
1-2-3:“哈!哈!哈!你不会是认真的吧?仿真红绿灯?还控制人类?”
火星人:“我当然是认真的,这个月的奖金就靠它了。”
1-2-3:“可是,我是说,既然你这么聪明——这么高级的UFO也造得出来,为什么还要来问我呢?你只要制作一个和红绿灯一模一样的东西就成了。”
火星人:“你的意思是说,我只要制作一个东西,它有3个不同颜色的灯泡,以及一个金属外壳……”
1-2-3:“没错。”
火星人:“那它必须要用电吗?你知道我们的飞船是不用电这种低效的能源的。”
1-2-3:“当然要用电,你只要简单地模仿就行了。”
火星人:“外壳的颜色呢?也很重要吗?”
1-2-3:“只是模仿就好。”
火星人:“好吧。那么外壳上面有多少个灰尘和细菌也要模仿么?”
1-2-3:“呃,这个……”
火星人:“外壳的温度呢?内部的温度呢?外壳对α和β射线的反射率呢?还有我们发现红绿灯会辐射2100~7600杰西卡的能量,这能量会造成0.027卡卡西的时空扭曲,而这扭曲又会导致大熊星座λ行星轨道产生2100哞喏的偏离……”
1-2-3:“好吧好吧,我算是服了你了。我直接告诉你好了,很简单——红灯停,绿灯行。”
火星人:“哦 哦,原来到底是哪种颜色的灯处于亮着的状态才是重要的。但是那个黄色的灯是用来干嘛的呢?”
1-2-3:“黄灯只是起一个警告的作用,不是很重要。”
火星人:“嘿嘿,你可不要低估我们火星人的智商哦。那个黄灯无论大小还是位置都和其它的灯一样,你却说它一点也不重要,这实在不合逻辑。”
1-2-3:“好吧,我就给你详细讲一讲。在绿灯熄灭后,红灯亮起前,黄灯会亮个十几二十秒,对于已经过线的行人,它表示:‘即将转为红灯,请快速通过十字路口。’;对于尚未过线的行人,它表示:‘请停止通行’。对于交通安全来说它很重要,可是对于你的那个以控制人类为目的的仿真来说就不重要了。要不要仿真它你自己决定吧。”
火星人:“很好,我的仿真的模型也决定了。我们决定忽略行人的移动速度这个属性,所以我们的模型是这样的:对于尚未过线的行人,绿灯亮则行,绿灯灭则停;对于过了线的行人,无论如何都要前进。所以我们的模型里只包括绿灯和行人这两个对象。”
火星程序员
当程序员想要编写一个针对陌生领域的仿真程序,他的处境不会比火星人强上多少。现实世界对他来说是个黑箱,但是使用黑箱方法进行研究将耗费大量时间且效果不彰。物理学家大多使用黑箱方法研究宇宙,是因为他们找不到上帝来问个究竟。
对于这个领域的领域专家来说,领域是个白箱。领域专家知道领域的所有细节,所有常见与不常见的情况,所有合理与不合理的处理方法。如果存在一个设备,可以把领域专家大脑中的所有领域知识提取出来,那么程序员就可以把领域作为一个白箱来研究了。然而这样的设备暂时还没有被研制出来,所以程序员必须具备侦探的本事。通过恰当的提问,敏锐的洞察力,通过大胆的想像和谨慎的求证,程序员得到对领域的深刻理解——领域模型。
但是这模型应该包含领域的哪些方面呢?是工作流程?是数据的流动和对数据的处理?是组织结构以及每个参与者的角色?是重要的事件、事务和时间?是法律、规则和潜规则?是实体和关系?是数据结构和算法?事实上,一个仿真程序几乎会包含上述所有方面,每个方面都同等地重要,只关注某几个方面的简单模型必然失去了其它重要的本质属性。如果一个模型包括所有属性又会过于复杂而无法使用一个二维图形来表达(文字描述也是二维的,所以才会有“说书的一张嘴表不了两家事”的窘境)。一般的做法是使用若干分别关注某几个重要属性的模型分别描述领域,它们最后在程序员的脑子里形成相互关联的整体认识。
我们将要重点讨论的是概念模型——使用合适的(包括创造概念上的)实体和关系来形成概念,阐述领域核心概念和原理的模型。
构建概念模型的目的是作为开发仿真程序的指导。所以从一开始就必须大致知道客户的需求——程序将为客户解决什么问题?它将主要仿真现实世界的哪些方面?
仿真程序并不是对现实世界的简单模仿,它或者比现实世界简单、或者比现实世界繁杂;或者比现实世界规范、或者比现实世界更加不规范……客户到底想要的是什么?什么是重要的?什么是可有可无的?这是程序员需要运用侦探技巧重点探索的。
概念模型深刻而简单。概念模型并不展现所有细节,它展现细节背后的概念和原理。程序员正是通过将模糊概念明确化、隐含概念显式化,甚至在必要的时候创造概念来逐步取得对领域的深刻理解。
程序员毕竟不是火星人,领域对程序员也不是完全的黑箱。即使是刚刚毕业的大学生,至少也知道什么是漂亮的、舒适的(本能层面);什么是简便的、有用的(行为层面);什么是礼貌的、友好的(情感层面);什么是合理的、合法的(文化层面)。如果已经开发过别的领域的程序,会发现有一些概念是相通的。这些已知的领域知识对程序员理解新的领域有很大的帮助,并且有助于程序员提出尖锐问题。
变成领域专家还是侦探?
程序员成为领域专家是可能的。有些程序员有条件与某个行业的领域专家长期接触,甚至就是领域专家的同事。经过几年甚至十几年的锤炼,这些程序员的领域知识可以与领域专家媲美,甚至知道的比单个领域专家更多。
另一方面,有些程序员不得不经常对全新的领域建模。他们发展了另一种才能——他们成了不折不扣的侦探。面对陌生的领域知识,千头万绪的细节信息,他们一开始会感到心力交瘁、焦头烂额。但是很快,他们灵光一现,理解了领域中的核心概念,然后慢慢地,一个完整的、深刻的领域模型逐渐浮出了水面。
事实上,并不存在纯粹的领域专家型或侦探型的程序员。即使是同一行业,每个客户的情况都或多或少有些不同;即使是同一客户,它的业务也在每天悄悄地发生着变化。所以领域专家型的程序员也必须得有点侦探的本事才行。对于侦探型的程序员,正如我们在侦探小说里看到的,出色的侦探都有着丰富的领域知识,他们总是显得什么都懂,每个细小的领域知识都可能成为破案的关键。
实用主义和官僚主义
没有人喜欢制作模型,就像没有人喜欢写文档。如果每天加班加点的垒代码都很难按时交付,谁还有心情去弄别的妖蛾子?对于一个程序来说,只有代码是必不可少的东西,其它的东西都是可有可无的。如果程序员们的腰包都鼓鼓的,时间很充裕,谁不愿把程序弄得跟艺术品似的?但是现实是客户有压力、老板有压力、项目经理有压力、程序员都在亚健康状态。建模的好处不过是一张空头支票,谁知道能不能兑现?
有一些公司特别喜欢制作“正规”的模型,通常他们也喜欢制作大量统一格式的“正规”文档。他们花大把银子购买正规的建模软件,花大量时间画漂亮的模型。可是,要知道制作文档所花的时间与这些文档和程序保持同步的可能性成反比。所以这些庞大的文档很快就与程序失去了同步,我们称这些已死的文档为僵尸模型。一旦模型成了僵尸,所有花在它身上的金钱和金钱买不来的时间就都白白浪费了,剩下来的,就只是漂亮的垃圾而已。当然,有些公司制作文档的目的是要通过XX认证,或者可以把文档卖给客户(确实有这样大脑袋的客户),这又另当别论。
我的建议是,只要向前迈一小步就可以了。如果你从未想过细节背后的概念和原理,那么可以尝试在有空的时候稍微深入想一下下。如果你已在主动思考概念和原理,那么不妨尝试把它们画在纸上,看能不能有助于思考?如果你已经把它们画在了纸上,但是从未把它们与同事和领域专家分享,可以尝试在下次讨论的时候边说边画。如果你真的很闲,可以用专业软件把它们画出来。但是不要以为画出来就万事大吉了,口头的讲解和讨论总是必不可少的。
详细设计书
在那些需求分析、设计与编码人员分离的公司,详细设计书备受推崇。详细设计书是设计人员与编码人员之间的桥梁。理论上,详细设计书包含书写代码所需的所有信息,编码人员不需要对领域有任何的理解,只要按照详细设计书的要求丝毫不差地编码即可。这样,设计人员在设计了一个项目并完成了详细设计书之后就可以去忙别的项目了。或者设计人员可以远在天边(例如外包项目)。但是详细设计书不可能包含所有细节,实际上是缺少相当多的细节,以至于编码人员来不及一一询问设计人员(或者设计人员已经找不到了),这时如果缺少清晰、一致的概念模型,错误和混乱就是不可避免的了。如果存在一位天才又勤奋的设计人员,他的详细设计书百分百的详细、正确、一致,那么这个详细设计书不可避免地要多达几千页,在这浩如烟海的细节中,编码人员必然会晕头转向,看了前面忘了后面。当然也可能碰巧编码人员也同样天才又勤奋,他一字不拉地把这详细设计书看了N遍,最终融会贯通,完全理解了其中真意。这其实是编码人员自己从详细设计书中推导出了概念模型——那为什么要这么麻烦,不一开始就给他一个呢?
百战不殆是可能的吗?
正如布鲁克斯在他的神作《没有银弹》里面所言,由于软件本身的复杂性和人类自身的局限性,软件开发工作很难一下子出现质的转变。但是在量的积累上,我们已经有了很多进展。我是指,几乎没有哪个领域没有仿真程序。有些领域甚至出现了通用产品,并且有了完整的理论。
我们都有这样的感觉,如果将要开发的软件已经有了一个使用多年的老版程序,那么工作将会轻松许多。领域专家会称赞它这里这里设计得非常好用,那里那里烂得不行;这几个功能每天都得用,那几个功能几乎没用过以及为什么没用。有了这些信息,再把那个老版程序玩透,就几乎可以得到对领域全面透彻的理解了。这个老版程序此时就相当于一个原型。
如果虽然这个公司没有老版程序,但是其它公司已经有了呢?如果已经有大好人把相似领域的概念模型进行了归纳和总结呢?所以,当4年前看到Martin Fowler的《分析模式:可重用对象模型》这本书时,我简直如获至宝。可是,4年过去了,这本书我一共看了20页不到——实在是看不懂哇。是我的实践不够?基础太差?人太笨?心法不对?还是太没耐心?我不知道……但是我坚信人类能有今天的辉煌书籍功不可没——别人十几二十年的思考结果我们十几二十天就能学到——站在巨人的肩膀上才能更高更远。我相信对概念模型的归纳、总结和分享可以在很大程度上帮助程序员快速成长。也许,以后大学里也会开设“领域知识”一类的课程。
小结
将油彩随意地泼洒到画布上能得到一副画么?不能。在钢琴上胡乱按上几下能得到一首乐曲么?不能。不了解领域知识的程序员能编写出程序么?能!但是,有多少迷惑就有多少猜测。最为可怕的是这些猜测又会成为其它猜测的根据。结果,使用迭代式开发的项目不多,使用叠加式猜测的项目不少。
但是我们不知道一个好的概念模型到底是什么样的,也不知道如何把它转化成实现模型。我们既不知道应该花多少时间在建模上面,也不知道它到底能给项目带来多大好处。至于是否能保持模型与程序的一致,我们更是没底。所以,我们最后都放弃了。我们对自己说,跑江湖,混口饭吃而已,还是土办法最有效。
不过,人类天生就有不断探索的欲望。我们一直在寻找更有效的工作方法。测试先行?用例先行?要我说,是理解先行!没有理解,一切都是空谈。
所以,不必拘泥于具体的招式。只要足够重视对领域的理解,不断探索,我们终究可以找到适合自己和项目组的招式。
下一篇将重点探讨具体的构建概念模型的心法。(预计年底发布)
参考文献
Model. Wikipedia.
Eric Evans, 领域驱动设计(影印版)。人民邮电出版社,2007。
史蒂芬·霍金 著,许明贤 吴忠超 译,时间简史(插图版)。湖南科学技术出版社,2007。
杰拉尔德·温伯格 著,张佐 万起光 董菁 译,系统化思维导论(银年纪念版)。清华大学出版社,2003。
杰拉尔德·温伯格 丹尼拉·温伯格 著,张凯 王佳 译,系统设计的一般原理。清华大学出版社,2004。
布鲁克斯 著,汪颖 译,人月神话。清华大学出版社,2002。
DONALD A. NORMAN 著,付秋芳 程进三 译,情感化设计。电子工业出版社,2005。
金庸,神雕侠侣。1976。