开篇之前我想先说说当年开发的那点事儿:大约10年前吧,我还是一个程序员的时候经常都是遇到这样的项目开发流程:
- 解决方案 :满足客户目的和投标用的一堆文档(不少还是互联网上抄的) ,是以Word为主的纯文字。
- 投标完成和客户付订金后项目组成立,通常为(0至1)个项目经理或者叫项目负责人+(1至N)个程序员 的项目组模式
- 设计:由项目的头或者经验最足的成员参与编写设计。倒霉的时候我们会得到一份按照软件工程学的纯中文形式的设计想法(抱歉我只能这样来形容),而更糟的情况是得到一份完全看不懂的Rose文档(那个年代可是UML大放异彩的时代,而当时我对UML完全就是个瞎子)
- 开发:到这里才有我参与的份,前面的内容通常作为项目组中低层的人员是不透明的。得到“设计”后,我们只能靠自己的“猜想”来实现,最后拿着界面给经理看是否符合他的“设计要求”。
- 测试? 这项目是没有的,只要程序能跑通直接就交付了。
项目的结果不言而喻,最多的沟通就是吵架与被训斥还有就是被客户抱怨。在这种例子很可笑,但更可笑的是至今我还听到不少的朋友跟我说起这种类似的苦B经历。他们不是没有设计,不是没有沟通也不是没有管理,只是每个人都在用自己方式在表达,没有共同的语言和沟通方式。那么换个沟通能力很强大的项目经理会改变这种境况吗? 可能可以,但遇到最多的只能是改善,只是苦B这个角色换成项目经理而已,因为本质上没有多大的变化。
我很感恩能有这么让人难受的开发经历,因为太难过了所以才促成当时的我去想办法,去学习最后努力去改变。接下来的部分会是我将这10多年来的经历进行的一些总结,因为我学的东东很杂当时在大学里根本没有这些知识只能靠在项目实践中摸索前行,我受MSF与敏捷开发的影响很大,并且我是一个反UML人士,但我并没有完全去采用某一种标准化的开发方法与开发流程,长年来只是以我对这些方法论的理解应用到我的项目里,而在这里我不想过多地讨论关于开发方法论与项目管理的内容,而只是将其中与架构和设计相关的内容抽取出来论述。
表达思维
架构师的职责
世界上最难的两件事是:将别人口袋的钱放到自己的口袋里面;将自己脑子的想法完整放到别人的脑子里面。在大家的印象中,项目经理是项目中沟通得最多的角色,其实架构师的沟通量也不逊于项目经理。在国内更多的情况是架构师与项目经理就是同一个人。作为系统/项目的总设计师,并不是单纯只为客户想出技术解决方案然后做出一份设计扔给项目组就完事了,而需要向每个位参与项目的成员或角色从不同的层面介绍或解释设计原意与理念。
有效沟通
本文的主要内容说得简单一点就是架构师销售自己的设计的一些方式与方法。除了开发能力与设计能力以外“有效沟通”也是架构师的很重要一项技能。架构师与项目经理不同主要工作时间与精力不是全放在沟通上,但如果沟通不当就会出现因为反复沟通而大量消耗架构师的设计时间,甚至设计出让人难以理解的架构,就算设计本身的含金量再高,在没有找到伯乐之前也只能处于“曲高和寡”的尴尬局面。我之所以将沟通看作一项修炼的另一个原因是这些内容都是从书看不到的,只能从实战中摸趴滚打慢慢积累而成,不同的经历可能也会有不一样的看法与心得,而接下来就是我积累多年的一点经验的总结:
如果说开发流程是大的迭代那么设计就是经历一次次的小迭代以至于完善,项目的每个参与者的想法与建议都是架构师修正设计,积累迭代的参考来源,。所以,架构师的沟通是需要双向激荡的。
我按照项目中与架构师沟通频率最高的角色、掌握的技能、信息的需求进行了归类,这样将更便于了解怎么样的沟通方式最为有效:
销售
- 沟通的需求:从设计中寻找卖点与特色,丰富销售方案和定制预售计划。
- 知识技能:对开发或深入的技术内容可能只存在于概念性的理解、掌握市场的第一手信息并且对客户的需求最为了解。
- 推荐工具:特色列表 (Full Feature List),字段:特色功能(Feature)+说明(Summary)
以产品开发(做项目会省事,没有这一步)为例,我与销售讨论整个产品的最具有特色的10项目功能(实际上3项就够了,实践告诉我只有前3项是别人记得最深刻的),这10项特色我们又称之为“购买理由”,然后是整个系统全部特色功能(Full Features)。我经常会与销售因为某个特色功能而经常激烈地碰撞,但最后销售所提出的意见与建议往往发挥着最重要的作用,有时甚至直接影响到项目的可行性。
修练的法门:
- 抛弃一切技术实现细节,写/说出产品最重要的三个特色
- 抛弃一切技术实现细节,用心聆听“非专业”的意见
项目经理
- 沟通需求:根据设计进行时间估算、准备项目资源与工作分解。
- 知识技能:大多是熟悉体系架构类的知识(需要了解他/她是偏向于技术还是管理),热衷于沟通与跟踪
- 沟通工具:Excel
- 图形工具:架构图、原理图
项目经理是架构师在项目中最重要的伙伴,因为他在负责跟踪与保证你的设计被实现的全过程,是项目资源的提供者与进度的控制者,他需要了解每一个检查点(CheckPoint)与里程碑(Milestone),这也是项目经理与架构师最重要的连接点(Connection Point)。我与项目经理讨论得最多的是系统实现的原理和实现各部分可能存在的难度和可能发生的风险。
修炼法门:用最简单的图形视觉化设计
以下这两个图是我为数不多的公开项目中可以拿出来作为示例的,我用的设计工具是Excel:
图例1:技术架构
图例2:应用程序架构
注:这两个图例是我的一个多年的开源项目DotNetAge CMS的架构图,有兴趣的朋友可以访问GitHub或者 DotNetAge (英文)官网了解其它的相关内容
开发
- 沟通需求:根据设计要求进行技术准备、部署开发环境、编写DEMO以及最终编码,关心自己所负责的技术细节与实现方法。
- 知识技能:掌握或精通特定的开发工具及开发技巧
- 沟通工具:范例代码
- 图形工具:序列图,状态图,类图
与开发人员沟通是最困难也是最有思想激荡的环节,开发人员就像是小朋友一般富有尝试新事物的胆气与想法,在没有制度与行政压力的作用下要让他们完完全全“遵守纪律”可不是一件容易的事。我并不认为架构师或者项目经理在地位与行政上要领导其它的成员,这种“自然层级”并不利于沟通,反而容易让项目组变成“一言堂”。我认为与开发人员有效沟通的最佳方法就是“用代码说话”,这也是为什么我在第一篇文章就提出架构师也需要是一个代码控的另一原因。
我们交付到开发人员手上的都是空的公共接口或是公共类,开发人员是不能随意改动任何接口、类、方法的命名的,这是一种最基本的约定,否则就乱套了。另外就是针对核心、多人使用、原理复杂的代码必须带有代码范例。代码范例就是与开发人员产生讨论与激荡的专用区域,也是为以后加入项目的人员提供的快速入门的最好途径,可以在很大的程度上降低不可见的、难实现、高风险代码出现的机率。
修炼的法门:一边设计一边写范例代码,让范例代码成为设计的一部分
测试
- 沟通需求:根据设计划分测试粒度、测试的覆盖范围、准备测试环境、定制测试计划
- 知识技能:掌握各种测试方法、对Bug的所在有着天然的直觉。
- 沟通工具:类使用参考
- 图形工具:架构图,序列图,状态图,类图
我认为测试人员的架构能力往往并不亚于任何的架构师。能从常规化测试(单元测试、界面测试)发现问题是最为初等的测试人员;能从系统性能、流程或架构中发现问题的测试靠的是经验,阅历甚至是一种直觉或者说是能“嗅”出问题的所在(在下一篇文章中我将会详细解释这种能力的源泉),这才是高级的测试人员。与测试人员的沟通与开发有点类似,只是当没有高级的测试人员配置时,架构师也只能充当这个角色,作为软件的设计师是最能了解自己的系统可能存在的问题,在沟通时这些“问题”就是沟通的重点,必要时需要反复地观察测试报告的结果,以找出“隐患”所在。在这里,所谓的修炼法门与上一点基本相同。
在此只对常见角色进行大至的分类,按我们采用的开发方法不同可能还会存在更多的其它角色如:RM(发布经理),TM(技术经理)等等就不作一一细分了。
驾驭方法论
前文更多在探讨如何向不同角色的人去表达自己的设计与思想的一些方法与见解,而作为架构师自身的能力也由为重要。对方法论的掌握、理解与实践就成为架构师真正的“本钱”,用流行一点的语言就是所谓的“核心价值(Core Value)”。
我是一个很愚钝的人,10多年来读了很多的这方面的知识但真正能理解并用起来的也就两三个,实在是由于环境、阅历所限,很多理论没有特定的环境也只能当小说看。通过对各种方法论的学习, 我悟到了一个心得:
“ 方法论的学习曲线是迭代的,也就是说同样的理论在经过不同的经历后再次重新学习就会有更深入的理解和新的领悟。”
单单是《设计模式》一书我就从来没有停止过迭代式的学习与实践,而每一次实践我都能得到一次新的领悟与体会。
我会在下一篇文章中讲述我认为最有迭代学习价值的方法论。
接下来就说说我认为在设计中很用的一些方法论,以及我对这些方法论的一些总结。
框架理论
“框架”一词近年来随着 .net framework 的成功推广感觉上都被用烂了,什么东东都会加上个XXX框架,可能是源于市场需求吧。我接触“框架”这个词或者说这个理论是在.net 诞生以前,在开始探讨框架之前,我在 WhatIs 上找到了一段在软件框架方面比较贴切定义:
原文:
In general, a framework is a real or conceptual structure intended to serve as a support or guide for the building of something that expands the structure into something useful.
In computer systems, a framework is often a layered structure indicating what kind of programs can or should be built and how they would interrelate. Some computer system frameworks also include actual programs, specify programming interfaces, or offer programming tools for using the frameworks. A framework may be for a set of functions within a system and how they interrelate; the layers of an operating system; the layers of an application subsystem; how communication should be standardized at some level of a network; and so forth. A framework is generally more comprehensive than a protocol and more prescriptive than a structure .
译文 【Ray】通常地一个框架是为了解释如何构建某项有用的事物及其结构的实现或概念的一份支持或指南。在计算机系统内,框架通常被用于描述一个程序应该构建的层次结构。某些系统架构甚至会包含实际的程序,接口或开发工具集。一个框架指的可能是一套相关的函数集合、操作系统内的某些层次、或者某个子系统内的层次又或者是网络中某个层次结构下的标准化通信方式等等。 一个框架通常比一个协议的定义更为全面,比结构的定义更为规范。
在设计上,我对框架的理解是:框架是用于定义并锁定对某个概念的理解范围与实现的边界,在既定的边界下可具体化至其实现、并能迭代进化的一份设计指引,是架构师手上总的设计蓝图。这是我喜欢使用的一种方法论,微软在MSF中的Function Spec (功能说明书)与之有点类似。它是一份对用户需求以技术架构形式第一次细化的一种输出。我喜欢这种方法论的原因是“简单”,“灵活度高”,不需要标准化(标准化的东西是不需要设计的只需要套用,那是模式),只需要掌握两种原则就行了。
建立蓝图(Build A Whole Picture)
在阅读框架文档时只即使所有内容都忘记了,只要整个设计图景能印在读者的脑海就达到目的了。这是一份指引,是思维的起点,有共同的图景自然就会产生共同的讨论点,锁定设计与话题的边界。同时也是系统进化的重要依据。
定义边界 (Compressive Definitions)
所谓的边界其实是对要画出来的模块的作用有一个明确并且清晰的文字表述,让读者能在建立全景蓝图后可以深入地了解每一个部分的具体含义,从而加深入系统的认识。
怎样学习
最简单的入手办法就是从你所熟习或者了解的系统入手,将其框架重新描绘出来。然后将你所了解的每个部分的定义套入其中,你将会发现你对现有的系统建立起一个全新的认知。而关于工具的话可以用最原始的纸和笔,熟练后用Excel的够了(想更为美观可以用PhotoShop), 最重要的一点是不要让工具分散你思考的集中度,所以简单就好。
至此,如果你开始尝试这个方法可能你就会明白,为何我这个系列的开篇需要花那么长的篇幅去说明成为架构师先得成为代码控的必要性,因为从蓝图开始既需要超越语言限制又需要对语言有深刻的了解。
UML
要成为架构师的话,UML则是一门必修课。相关的资料与学习资源极其丰富,至于相关的学习方法也非常个性化,能掌握就好在此不作过多的赘述。在此,只是想分享一些我在学习和使用UML的一些心得。首先,在入手UML前必须非常熟悉对面向对象的所有基本概念否则基本上是浪费时间的。然后是有选择性的学习,UML毕竟是一个非常陈旧的方法论即使到2.0版本如果真的全部安照UML的理论作为核心开发指导会非常坑爹,它是个重武器!看看当年最牛X设计工具: Rational rose 虽然强大,但我觉得它更像个玩具。他的所谓文档也只能是设计师级的人看的,由其是Use Case基本上是个集丑陋与非人类思想为一体的图形,我基本上不用,因为他在与人沟通和整理自己思路上显得极为不便,还不如用文字直接写两句话能说明问题(纯属个人的吐槽)。
UML是设计的常识或者说用于建立共同的设计语言,但不要以其为蓝本,它在发现类,抽象出接口、梳理类或类与类之的关系和交互性时有重要的作用。我的方法是只学图形不学过程,能让人看得懂的才是设计,也不需要特意安装什么UML的专用工具,优秀的IDE一般都会带有一些基本的UML图形工具,比如:VisualStudio 。简言之:UML只是共同语言,“活用就好”。
设计模式
设计模式是架构师解决复杂问题的一把双刃剑,用好了问题可能会被大大简化甚至是巧妙地解决,但用得不好可能也会让体系架构出现不可控制的膨胀而变成一个糟糕的设计。面对设计模式理念我们需要以清晰的态度面对,当我们理解或掌握某种模式时肯定也会有一种尝试的冲动,但请不要将这种头脑发热式的行为应用到设计中来,有冲动就去做一个实际的范例。在理论上掌握与实际理解毕竟会有一段距离,将这种浅层次的理解直接放到设计中,一旦运用不当就会控制不住类的规模而造成设计错误。前面这些话不是让大家不去用设计模式而是需要慎用、活用,吃透了再用,为了能掌握它们我也吃不了少的苦头,在此总结出一些运用的经验,以供参考:
明确动机
不要为模式而模式。模式本身是针对解决某一问题域所提出的一个高度抽象的对象模型,每种模式都会有明确的使用动机的说明,这个动机与我们的实际的需求是否匹配是衡量其适用性的标准。
建立局部架构
在使用模式前,建议独立的创建一个工程。把模式以TDD的方式边实现,边测试。网上虽然存在很多的模式实现的“例式”,但很多都写得糊里糊涂的,真正能用的并不多,值得推荐的只能数Enterprise Library 了,它以模式为其础也加入了MS的实践算是一个设计者入门的宝库。虽然EL的代码很多,不过运用我在第一篇所提到的看代码的方法来学习也不会很吃力。在开发人员使用工程的公共接口和类以前,架师最应该做的就是模型测试, 采用了设计模式的架构最为有效的文档是范例代码,这样可以避免去解释内部原理的时间,开发者就是使用者会用就好。另外,作为设计者本身,写范例代码可以验证设计的准确性与正确性,而对于测试用例的编写也一份重要参考指南。有了范例代码我们就可以同时向两种角色(开发、测试)交付实际的设计结果。
理解组合的效果
标准的23种模式并不单单是独立的,模式与模式之间的互用往往会产生1+1>2的效果。但同时需要注意的一点是,增大使用效果的同时也会同样的增加系统复杂度。
设计模式是架构师伴侣,她是为解决问题简化问题而生的。综观23种模式都是在不同的场景围绕 耦合度、封装性、易用性为核心论述,因此我检验运用模式效果的简单标准是:
- 耦合度是否被降低了?
- 实现细节是否已被接口隐藏了(封装性)?
- 外部接口实现是否简单?
测试驱动(TDD)
大家都知道测试的重要性,但运用于实际的并且贯彻整个开发过程的并不多见。可能是“测试”的可选择性与“Quickly and Dirty” 的思想让测试始终没有被放到一个绝对重要的位置上去。说实在话我也是最近两三年才完全地体验到TDD给我带来的方便性与认识到其中的重要性。由其是设计规模庞大的项目时,架构师再强也不可能考虑到全面的细节问题,由其是代码实现。而MOQ这一类的工具类库的出现也非常好的帮助我去模拟出类被实现后的效果,能直接测试出模型中可能存在的隐性或显性而被忽视的问题。在团队配合开发的流程中测试的作用更是贯穿全局。好的测试流程可以在无沟通的情况下让项目经理了解每个CheckPoint的完成情;让架构师能模拟实现,测试类模型和编写使用范式;让开发人员可拥有最小化的代码运行入口;正如前文所提到的,一名高级的测试其设计能力可与架构师并肩,他们能从表象中发现架构中可能隐含的问题所在。那能不能反过来说一名架构师也应该具有高级测试的相应能力?很明显答案是肯定的。架构师最起码的需要掌握的是测试驱动的相关知识,最起码了解如何写单元测试、顺序测试并能使用MOQ来模拟接口实现等的基本测试方法。
小结
这一篇文章我并没有与上篇一样给出一些具体的方法,因为本文讨论的更多的是我仅有的一点点经验的总结,而更多的是来源于思维上的。我极力地想用有限的文字能力去表达这种意识和思维,最终却仍然觉得有很多的内容未必能尽说,或者你也可以尝试通过实践来去检验我以上的理论。而在下篇中我将会更为深入地讨论在设计中我认为高层次的内容:“变化”,我一直想多举出一些实例而并不想写得与到处可见的“干货”般无味,最后还是那句:敬请期待吧。