软件设计 实践




1)什么是优秀的设计?
2)优秀设计从分析需求开始
3)软件系统不是木桶型的
4)软件设计的“大道理”
5)规划系统的骨架——架构设计
6)打造系统的底蕴——数据库设计
7)细节决定成败——详细设计
8)用户感觉好才是真的好——用户体验设计




1)什么是优秀的设计?

1.1.  什么是优秀的设计?

某项目的设计文档评审会上,各路技术大牛进行了“热烈”的讨论,讨论的焦点是怎样的设计才漂亮!大家围绕着如何OO,如何高内聚低耦合,如何反转控制等话题进行了“热烈”的争论。

你觉得以下标准可以成为“漂亮”设计的标准吗?

1)高效
2)可靠
3)易用
4)安全
5)可扩展
6)兼容性强
7)移植性强
……

如果每次设计文档评审,我们都采用上述标准来评审,你觉得这个设计评审会有效果吗?

当时我参加了这样的一个设计评审会,觉得气氛很不对,照这样开下去,这个评审会岂不是变成了“神仙大会”!

于是我问了两个问题:

1)谁能说说这个项目的主要需求
2)这些需求,设计上是如何考虑实现的?

结果没有人能答上来!

我们从书本上看到的那些”通用“的设计标准,说得难听一点,就是废话!对实际的项目工作基本上没有实质用途!


请看下面4个例子,分别思考这4个案例的软件设计思路,你会发现上述“漂亮设计的标准”,真的是废话!

案例1:某项目要求在很短时间内完成,而且客户对系统的当前认识还是比较初步的,你打算怎样设计这个系统?

案例2:某软件公司接了一个“网页+数据库”类型的项目,这类项目已经做过多个,但这次的业务却是新的,你怎样考虑这个项目的设计?

案例3:某软件公司已经成功为n个医院做了管理系统,现在需要为一家新的大医院做类似这个系统,你会怎样考虑这个系统的设计?

案例4:你接到一个任务,要做一个即时战略游戏,目标是要在当前游戏市场找中杀出一条血路,你怎样考虑这个游戏的设计?


4个案例各有特点,分别代表了4种“典型”:

案例1:需求很朦胧,工期很紧,技术上基本上没有积累。

案例2:需求是新的,但可以重用“网页+数据库”的技术架构。

案例3:需求是类似的,技术架构也是类似的,相信你会直接重用之前的系统。

案例4:这是一个需要创意和高技术含量的游戏,而游戏软件的需求和技术都是充满挑战的。

上述4种情况,相信你采取的设计策略是不一样的,你可能会发现所谓的优秀设计没有固定的标准


如果硬是要来一个优秀设计的标准呢?

我会这样说:就是做高性价比的设计

一个优秀的设计应该具备以下特点:

1)优秀的设计都是需求驱动的,不熟悉需求就做出来的设计是不靠谱的;
2)优秀的设计应该是当前团队能理解能实现的,太超前的设计项目团队做不出来,这个设计只能是摆设;
3)优秀的设计应充分考虑当前各种限制条件,适当做出平衡,能保证达成项目的目标:
4)优秀的设计能尽量降低项目的整体工作量,让整个项目更加可控。



1.2.优秀的设计能节省项目工作量


关于软件设计的话题,如果脱离一些实际案例讨论的话,很容易变成空洞无力的学术讨论,所以本文将会列出很多案例供你参考。


设计案例:开发某线上社区网站

背景:某社区已经举办了多期沙龙活动,为了拓展沙龙的影响力,让更多朋友受益,树立良好品牌,将来实现盈利,有必要建立一个线上的社区网站。

该网站应有这样的功能:

1)发布各种活动信息。
2)发布业界新闻。
3)能开展线上沙龙活动,包括在线视频沙龙。
4)具备SNS社区,可汇聚人气。
5)每位会员有自己的博客,能维护自己的个人页面。
6)支持简体中文、繁体中文、英文三种语言随时切换。
7)支持全文搜索。

你打算如何设计上述系统呢?


你可能会问,有工期限制吗?

你说呢?真实项目一定会有工期限制的,这个项目你的工期只有1个月!

你可能会说:你当我是神仙啊,1个月有可能怎样死都死不出啊!

这个时候能帮助你的就是优秀的设计,优秀的设计有可能能让你用很少的工作量就做出来,优秀的设计也不一定需要你全部从零开发的,我们可以拿来主义!有不少开源软件是可以基本满足上述要求的,我们可以直接拿来用,这样你需要付出的工作量就少很多了。


我曾经用某开源软件做了这样的一个网站出来,但发现没有全文搜索功能,结果我想了一个“投机取巧”的办法,自己不写一句代码,直接利用谷歌的这个搜索功能“site:域名 关键字”,让谷歌帮我搞定全文搜索。当然这样做出来的效果还不是很完美,但至少我能在很短时间内能做出个大概啊,如果自己开发还不一定能做出这样的效果呢!


小结:

受工期限制、受能力限制等制约因素,十全十美的设计基本上是很难做到的,但如果因为赶工期而在软件设计上节省时间甚至是直接忽略这步,其实是得不偿失的。在软件设计上“节省”1小时,可能会让你将来多投入成倍的项目时间;越是工期紧,越需要冷静思考软件的设计,合适的设计能大大地降低项目工作量,让你后期的工作轻松很多。







2)优秀设计从分析需求开始

设计应该针对需求来做,这个大道理似乎人人都懂,但实际操作时往往就不是这样。所以我们 也不说大道理,直接通过一个“很简单”的案例来体验一下优秀设计应该如何从分析需求开始。


2.1 案例挑战:考勤系统的软件设计


某公司要做一个内部用的考勤系统,希望达成以下目标:

1)规范员工的上下班、请假、外出工作等行为。
2)
方便计算员工的薪金。
3)方便管理各种带薪假期。

你如何考虑本系统的设计呢?

你可能会说:我靠,才三句话的需求,怎样做设计呢?

说得太好了!我们做软件设计的,第一步并不是直接去设计,而是分析需求!


2.2 如何分析需求


当你接受一个项目的设计任务时,可能会遇到比较尴尬的情况,那就是需求有问题!

具体的情况可能有:

a)需求很简单,几句话或者是一页纸的需求。
b)需求很详细,可能有几十页甚至上百页,这些需求是招标书中提供的,或者是客户直接提供的。不要以为有这么多需求是好事,这些需求通常是前后有点矛盾、逻辑有点混乱,甚至是不知所云滴!

c)你们有专门的部门或者专职完成了需求工作,提供了一份需求文档。你也不要以为这是好事,因为很可能会出现这样的情况:需求文档的提供者认为自己写的需求文档很牛逼,水平很高;但负责实现的开发部门认为该文档质量太差,比方说:不考虑实现的可能性和难度,没有考虑到客户的真正需求等等。有时候甚至出现开发部门忽略掉需求部门,直接找客户重新调研,重新编写需求文档的情况。


上述三种情况一句话总结就是:需求的质量有问题!

我们需要重新分析一次需求,先从业务角度审视一次,然后再从软件设计的视角审视一次。通常我们需要按顺序思考以下问题:

A)什么人会使用这个系统?  用例图
B)不同的人将会使用这个系统的什么功能?  用例图

C)还有哪些不确定或不具体的需求点?  用例图
D)哪些需求对技术提出了怎样的要求? 用例图
E)系统的大致架构应该如何考虑?  部署图

下面开始我们看几个图,按顺序逐一思考一下上述的几个问题。本小节回答问题1、2,后面的小节回答其他问题。


A)什么人会使用这个系统

不少技术人员分析需求时往往是技术的视角,当你问他系统有什么用户时,你可能得到的结果有两种:

a)没有什么用户啊,所有人都是用户,因为系统只需要配置一下权限,谁都可以用。
b)系统有两种用户,就是:用户和管理员。

我们从业务的角度来审视一下考勤系统的可能用户,请看下图:


图2.1 系统可能用户分析


此图列出了如下可能用户:

employee:员工
finance:财务
receptionist:前台
manager:经理
senior manager:高级经理
administrator:管理员

而上述用户还有这样的关系:finanace(财务)、receptionist(前台)、manager(经理)继承employee(员工);senior manager(高级经理)继承manager(经理)。

用户之间的继承关系,是什么意思呢?

我们都知道代码中B类(子类)继承A类(父类),子类就具备了父类的特点。用户之间的继承关系是相同的意思,我们继续看看下图你就可以理解了。


下图将会回答这个问题:

B)不同的人将会使用这个系统的什么功能



图2.2 系统的需求分析


图2.1和图2.2都是UML的用例图,两个图加在一起比较完整系统地表达了以下问题:

a)什么角色会用本系统?
b)这些角色通过本系统分别能干什么事情?
c)角色之间有可能会有继承关系,请留意父类能干的事情,子类也能干,例如:employee可以打卡,manager也可以打卡,尽管图2.2中manager没有直接与”打卡“相连,但图2.1中已经说明了manager继承employee。

UML是需求分析的有力工具,我的工作中很喜欢用UML。但你的工作中、你的需求文档中可能会没有UML图,不管你们是否用UML图,分析需求时都需要从业务的角度思考这些问题

a)什么人(角色)会用这个系统?
b)这些人(角色)分别需要用系统的什么功能

需求分析其实是一个复杂的高难度的话题,回答上述两个问题仅仅是需求分析的第一步而已,我们还需要深入分析业务,包括业务流程、业务数据结构等等。如果之前的需求工作不到位,就需要我们立马开展软件设计工作,其实将会埋下很多地雷,后患无穷。



2.3 找出设计关注点


本小节我们回答这两个问题:

C)还有哪些不确定或不具体的需求点
D)哪些需求对技术提出了怎样的要求

软件设计师需要有敏锐的需求及设计触觉,看着图2.1和图2.2 嗅出一些问题,你能嗅出一些问题吗?

请看下图:


图2.3 系统的设计点分析

图2.3主要从设计的视角对需求再进行一次审视,以下是一些建议:

a)你需要更加深入思考需求,考虑到各种不同的业务场景和特殊情况,例如:领导不在公司时如何审批请假?
b)你需要思考需求的细节,例如:报表的具体形式?
c)你需要思考各种技术方案,例如:打卡数据的同步方案,财务软件是否要对接等等?
d)你要做出平衡,用合适的方案和尽量少的工作量来满足需求。


2.4 针对需求做初步的架构设计


本小节将会回答这个问题:

5)系统的大致架构应该如何考虑?(从部署图开始考虑)


接下来你要做初步的架构设计了,架构设计是难度很高的事情,需要你全面考虑需求,考虑工期限制预算限制,考虑项目组人员的水平,而做出的一种平衡。请看下图:


图2.4 系统架构的考虑


图2.4是UML的部署图,这个图比较粗糙,而且为了降低大家阅读难度,我仅仅是用了部署图的最基本最少的语法来表达。

图2.4中的每一个立体的矩形,表示的就是物理上或者是逻辑上的一台设备,设备之间 有物理连接的话就用线条连接,每台设备中”{ }“括起来的文字是对该设备的进一步说明。

图可能是表达设计的最好方式,建议大家用UML,表达系统架构时,用UML的部署图、组件图和包图是比较合适的。我们设计的系统多数是分布式系统,不是单机系统,用部署图来表达分布式系统的架构设计可能是比较合适的。

图2.4针对图2.3中提出的问题进行了初步的回应,图2.4 就是一个初步的架构设计,当然后续我们还需要继续细化这个设计。


2.5 小结:如何需求驱动设计?


本篇的例子告诉我们:

1)优秀的设计是需要从分析需求开始的。
2)需求的质量可能有问题,那么我们需要从业务的角度重新审视一次
3)从设计的角度审视需求,我们会提出很多需求细化及设计方案的问题。
4)架构设计是全面考虑各种需求、项目的工期限制预算限制,还有项目组人员水平后综合做出来的一种平衡。







3)软件系统不是木桶型的

3.1 某种“需求直接驱动设计”的工作方法


案例分析:某敏捷实践项目小组的设计方式

某项目小组正在如火如荼地实践敏捷,任务看板上已经粘贴了很多“用户故事”,项目小组经常在看板前讨论问题:

1)讨论每一个用户故事的实现方法,并进行估算;
2)项目小组成员领取用户故事,负责实现该用户故事;
3)每天检讨进度情况和遇到的问题。

该工作模式给项目小组带来了新鲜的动力,调动了大家的工作热情,取得一定的工作成绩,但也带来了一些思考:

1)只要我们将每一个用户故事的设计想好并实现,每个用户故事都能通过测试,软件就能完成?
2)用户故事之间没有关系吗?软件设计不需要统筹考虑全部的用户故事吗?


3.2 软件是木桶型的吗?


请看图:


图3.1 软件是这样工作的吗?


一般我们的系统会采用分层架构,以三层架构为例子:

1)最外面的是表现层,主要就是程序的界面了;
2)界面后面就是我们写的程序;
3)程序后面就是数据库。

按照上述的“需求直接驱动设计”的工作模式,只要有新的需求,其实就是有新的用户故事,那么在这个用户故事驱动下,直接设计对应的界面、程序和数据库表就行了。这样的框架下工作,我们可以无惧需求变更。软件就是一个大木桶,需要实现更多需求,那就增加更多的木条就可以了;如果要修改需求,那就修改某条木条就可以了!


我发现很多系统是按照这样的思路来设计的,举一个某电信网站的例子。

我到该网站交费,发现有免费宽带提速的服务,需要输入电话号码来确认该电话线路是否具备提速的条件。我觉得很郁闷,明明我已经登录系统了,系统应该知道我的电话号码,为啥还要我填一次?好吧,为了免费提速,我就输入一次电话号码吧,提交后系统告诉我一个订单号,告诉我大概什么时候会搞定之类的信息。过了几天再次上这个网站,免费提速宽带的窗口又弹出来,我很烦关掉它:我已经提交订单了,还干嘛一直提示我!但它又继续弹出来,我烦了,那再提交一次订单吧,居然可以提交成功!被这样的系统折腾几次其实也不算什么,只要能免费提速也就值了,但最终的结果是电信一直没有帮我提速,我也懒得去投诉了,按照我以往投诉的历史经验,那是折腾自己的事情!


很多商家在不同时期有很多的促销等市场活动,需要软件系统来支持。我们按照木桶原理来做系统的话,看上去似乎事情变简单,但功能与功能之间其实存在很多交叉点,不考虑这些情况,会导致很多问题:

1)首先是用户体验超级不爽。有些系统甚至没有做到用户信息和权限信息共享,就好像上述这个电信例子。
2)没有能发现功能与功能之间的“重用”部分,没有从架构上和数据库底层上认真规划,其实会带来更大的总体工作量。
3)会留下一些系统漏洞甚至是安全漏洞,万一出问题后果很严重。


3.3 软件的内部架构是怎样的?


请看图:


图3.2 软件常见的工作模式


此图说明了以下问题:

1)需求并不是由一个个孤立的“用户故事"组成的,业务概念、业务流程其实是贯穿多个用户故事的,软件设计应该多从业务概念、业务流程的角度来思考;
2)表面上看上去一个用户故事对应一组界面,其实界面之间是很可能有重用和共享部分的;
3)业务逻辑层中的一些类很难将其分拆开来与用户故事、界面组一一对应,存在交叉、共享和重用的可能;
4)数据操作层的代码,有可能是用工具自动生成的、通用的;

5)数据层中的某张表,通常会支撑多个用户故事而不是一个用户故事。


下面我在列举一下无法单独考虑的设计点,以下列出来的可能都需要从软件架构上做一个整体的考虑:

1)权限控制;
2)性能要求;
3)日志记录;
4)工作流;
5)全文搜索;
6)多数据库支持;
7)搜索引擎优化;

……


实际上很少需求是可以通过单独添加一些类,加一些数据表就搞定的,需要通盘的考虑。如果我们硬生生地将系统看成是木桶型的,去添加系统的木条,会让软件很丑很难用,存在诸多漏洞,而且工作量会更大。


3.4 小结


有时候由于目前能力有限,无法全面考虑需求,只能暂时按照木桶型的方式来设计系统,这样也不是不可以的,但要注意的是至少要做到:

1)用户信息和权限信息是共享的;
2)要杜绝安全漏洞。

木桶型的设计方法其实会让系统很难用、弹性很差、工作量更大,而且部分需求我们无法通过添加木条的方式搞定,我们需要尽快升级我们的设计水平,下一节开始为你介绍比较实用的软件设计方法。





4)软件设计的“大道理”

4.1 我的第一次商业软件的设计经验

1999年刚毕业不久,我从事第一份软件开发工作,当时要负责一个大型桌面软件,但不知道应该如何开展软件设计工作,于是向老板请教。老板也仅仅是年长我几岁,不过公司的核心产品是老板开发的,老板说他其实也没有什么系统的方法,不过有两种思路供我参考:
1)先假设软件已经做出来了,想好软件的外在表现,由此 倒推软件的实现方法
2)思考 程序的数据结构,先设计数据库,然后再搭建软件的上层建筑。
上述的两种软件设计思路,相信很多有软件设计经验的朋友都能体会到。后来我又体会到第三种的设计思路,后文将会为你分享我对这三种设计思路的一些体会。


4.2 N层架构是怎么回事?

这三种设计思路都与软件系统的N层架构有关系,我们以常见的四层架构为例子,请看图:


图4.1 四层架构

这个是UML的 包图(Package Diagram),图中好像文件夹的那个东西就是“包”,包与包之间的虚线箭头表示的是依赖关系。
上图表示的意思如下:
1)四层架构的四层,分别是指: 表现层、逻辑层、数据访问层和数据层
2)表现层 依赖于逻辑层,逻辑层依赖于数据访问层,数据访问层依赖于数据层。

那“依赖”是什么意思呢?
“依赖”可以是以下情况之一:
1)A需要调用B的方法,则A依赖于B;
2)A的方法中某些参数的类型是B,则A依赖于B;
3)A的某些方法的返回值类型时B,则A依赖于B。

这样我们大概了解了四层架构是怎么回事了,但我们还会有以下问题:
1)表现层如何将数据传递给逻辑层?
2)逻辑层如何将数据传递给数据访问层?
3)数据访问层如何将数据传递给数据库?

通常我们不会这么老土通过一大堆参数来传递层与层之间的数据,通常我们 会将数据装在实体类中,通过实体类来传递数据。所以图5.1可以进一步表示为图4.2:

图4.2 四层架构与实体类

补充说明一下什么 实体类
实体类通常是一个只有属性没有方法的类,通常我们会将某一业务对象的数据装在一个实体类中。例如:某请假单实体类,该类可能有请假人姓名、请假起止时间、请假类别和请假事由等属性。


4.3 “由顶而下”的设计思路

看了图4.1和图4.2,你大概就清楚了什么是软件的“顶”?什么是软件的“ 底”?“ 顶”就是表现层,“底”就是数据层。那么“由顶而下”的设计思路,其实就是先想清楚软件的表现层,然后再思考逻辑层、数据访问层、数据层的实现。
前文我们提到要 “需求驱动设计”,这个说法有点笼统,我们需要进一步思考: “什么需求”驱动“什么设计”
请看下图:

图4.3 由顶而下的设计思路

这是UML的活动图,横线将图分成了上下两部分,上部分是 需求分析,下部分回答了“什么需求”驱动“什么设计”的问题。
说明一下:“需求驱动”及横线不是UML图的标准语法,图加上这些非UML元素是为了更好地表达问题。
“需求分析”这个活动有三种工作产品,分别是:
1) 用例/用户故事
2)业务 流程图
3)业务 概念图
你可以理解为上述三种工作产品是“需求分析”这个活动的“输出”。
“用例/用户故事”和“业务流程图”是“规划界面”这个活动的“输入”;类似,“业务流程图”和“业务概念图”是“设计逻辑层”这个活动的“输入”。其他就不再多解释了,你应该可以看懂这个图了,后续几个图的语法类似,也不再解释了。

上述是对图4.3语法及表达意思的基本解释,这里再稍微小结一下:
1) 分析需求是设计的开始,我们还需要将需求至少分解为三部分:软件要满足的功能(用例/用户故事)、业务流程(业务流程图)、业务概念(业务概念图)三部分;
2) 设计不同的层时,主要依赖的需求是不太一样的,上述分解的三部分需求对不同的层设计提出了不同的要求。比方说:设计数据库时主要是根据业务概念来设计的,规划界面时主要根据软件需要满足的功能点,还有业务流程来设计。


4.4 “由底而上”的设计思路

经过前面的铺垫后,这个“由底而上”的设计思路,相信你一看图就可以懂了。

图4.4:由底而上的设计思路

这个图也分成了上下两部分,上部分的内容其实和图4.3是一样的,只是左右顺序不太一样而已。


4.5 “由中间到上下”的设计思路

这种设计思路是我从事软件研发工作若干年后才认识的,当时是因为项目出现了特殊状况,为了应对这样的状况而采取的一种设计方法。

案例分享:客户要改SQLServer为Oracle
签订合同时,我们和客户约定的项目技术架构是.net+SQLServer,当时客户没有反对,我们就按这样的技术架构完成了系统,并且部署上线。但是不久客户居然提出了这样的要求:要求我们使用Oracle数据库,而不能用SQLServer数据库!我们通常是按照“由底而上”的思路来设计软件的,如果数据库要更换,基本上整个软件就等于重做!
如果你遇到这样的状况,你会怎么办呢?能不能按需求变更来处理呢?只有客户愿意付钱,我们就愿意干!但客户愿意付钱吗?这可是要付推翻重做的钱啊!!

最后我们的领导决定免费重做,领导决定免费重做的原因是:
这是公司的一个核心项目,我们期望这个 项目将来能产品化,能持续赚钱。但我们技术选型主要是根据我们当前的技术情况来决定的,没有充分考虑客户的情况。客户是某重要行业的企业单位,单位体制内的所有企业基本都是用Oracle的,但我们选择“视而不见”,选择了我们最熟悉的SQLServer来开发系统,其实迟早是要遇到问题的。客户除了用我们的系统,还会用其他更大型的更重要的系统,客户的其他系统基本上都是使用Oracle数据库的。所以如果我们要在这个客户领域打开市场,将项目做好,就有必要将系统改造为Oracle数据库。

但是我们已经有部分客户使用了我们的基于SQLServer的系统了,将来也有可能会有部分客户要求用Oracle,所以我们领导决心改造软件的架构,要让我们的软件可以支持SQLServer,也可以支持Oracle!于是我们按照“由中间到上下”的思路,重新打造了软件架构,请看下图:

图4.5 由中间到上下的设计思路

这个图也分成了上下两部分,上面部分和前面的图内容也是一样的,但下面部分就很不一样了,而且可能比较难理解。
“由中间到上下”基本的思路是这样的:
1)先不考虑表现层,也不考虑数据层;
2)先定义 实体类和数据层接口
3)接口定义好后,往上可以设计逻辑层和表现层,往下可以设计数据层接口的实现和设计数据库。

按照这样的设计思路做出来的软件架构,应该是这样的:

图4.6 由中间到上下的系统架构

图中见到数据操作层接口有两种不同的数据库实现,分别是SQLServer和Oracle,如果要考虑第三种数据库,那么再增加一个实现就搞定了,而系统的上层建筑(表现层、逻辑层)不需要改变。

这样的设计方式看上去很酷,是不是应该所有系统都要考虑用这样的方式来打造呢?
不是滴,这样的设计方式是有缺点的:
1)系统将不能充分利用数据库的特性,一 般会禁止在数据库中写存储过程、触发器、甚至是视图等,程序的的性能其实会降低;
2)因为不能充分利用数据库本身的特性,所以大部分甚至是 全部的业务逻辑只能靠程序搞定,这样其实增加了程序的复杂度和工作量。

所以每种设计方法都是有针对性的,都很难做到十全十美,一般只能针对主要矛盾做出一些取舍。


4.6 小结

如果系统没有多数据库的要求,我会比较建议你用“由顶而下+由底而上”的设计思路;如果程序需要支持多数据库,那么可能考虑“由中间到上下”。上面介绍的三种设计思路,其实在实际工作中我们往往不会只选其一,往往是结合了多种思路的。不要局限自己的思路,软件设计的可能性是无穷的。






5)规划系统的骨架——架构设计

5.1 从概要设计、详细设计说起

最开始我对概要设计和详细设计的理解是这样的:概要设计就是初步的比较粗线条的设计,详细设计就是详细的能指导编码的设计。其实我的这个理解比较“废”,基本上“概要“和”详细“这两个词啰嗦解释而已,其实当时没有见过这两种设计的实际案例,更加不清楚概要设计和详细设计的界线在哪。
我刚开始做程序员的时候是没有什么设计文档的,但有时我会主动写一些,也没有什么格式和模板要求,自己觉得需要就写而已。后来我们开始要写概要设计和详细设计文档了,我们写这两个文档不是为了规范化而规范化,而是希望文档能有效果,我们的做法是这样的:
1)我们 参考业界标准和自己的实际情况,制定了概要设计和详细设计的模板
2)项目写设计文档时 建议套用模板,但不必局限于模板的格式;
3) 概要设计文档是必须有的,而详细设计文档可由项目组决定是否需要。

我觉得写规范的设计文档是必要的,不能老是土法炼钢的模式来开发软件啊,于是我开始“正式”写概要设计和详细设计文档,但是慢慢产生了一些困惑:
1)概要设计要写到怎样的程度,确实没谱,基本上都是“凭感觉”,能规划出系统的大致架构以及各部分的关系就差不多了。
2)详细设计是不是描述出关键算法、设计思路就OK了,是否有必要进一步细化到类名、方法名、参数类型呢?文档需要写得这么详细吗?是不是直接写代码更好呢?
3)数据库设计是概要设计还是详细设计呢?
4)软件的外在表现、人机交互的细节、界面风格字体大小等等这些,应该是详细设计文档要考虑的吧?
渐渐地我们发现不能在局限在概要设计和详细设计这两个概念的框框内,我们觉得软件项目至少需要四方面的设计,就是: 架构设计、数据库设计、模块设计和用户体验设计


5.2 架构设计、数据库设计、模块设计和用户体验设计

我们先大概看看这四种设计是怎么回事?
架构设计:近似于概要设计,其实也可以叫 “概要设计”,但我觉得“架构设计”这个词可能更合适。架构设计需要通盘考 虑需求后,从宏观上规划系统的各个部分以及各个部分的关系
数据库设计:对 需求中的业务概念进行系统分析后,设计出 表和表关系、视图等数据库元素。
模块设计:类似于 详细设计,通常详细设计是一个文档,但模块设计文档可以有多个。架构设计将系统划分成多个模块,模块设计就是针对某些或某个模块的具体设计了。
用户体验设计用户体验是指用户使用软件时的整体感觉,用户体验设计需要考虑清楚软件的整体界面规划、界面先后关系、文字表达、软件与用户如何交互等等。用户体验设计是“由顶而下”设计思路重要的第一步!

我做的项目中通常每个项目至少需要1份架构设计文档、1份数据库设计文档、0到多份模块设计文档和1份用户体验设计文档。 但需要特别说明是:这四种设计其实不代表四种文档,仅仅是说明了四种类型的设计而已,设计文档的格式和数量是不限的,文档的名字也是没有规定必须叫什么的。软件设计是有无尽的可能性的,不要被文中的说法局限你的思维。

本篇重点介绍架构设计,其他三种设计请留意后续文章。


5.3 不要“放之四海而皆准”的架构设计

架构设计是从宏观上规划系统的各个部分及各部分的关系,那怎样表示系统的”各个部分“和“各部分的关系”呢?我们看两个案例。

案例1 :用分层架构表示的软件架构
如下这个图的表示方法合适吗?

图5.1 分层架构
你可能会发现,这个图不是在前面的系列文章中见过吗?没错,这就是前一篇中出现过的图。
某一次我作为面试官面试一位应聘软件设计师岗位的应聘者,我让他画图表示一下他曾经做过的一个项目的架构设计。他当时就画了一个三层架构的图给我,不过不是用UML图,而是用简单的几何图形(矩形、圆形、线条等)画出来。其实不用UML图画架构设计也不是很什么大问题,问题是这样画出来的设计是不是太粗了?是不是“放之四海而皆准”?他画了这个图后,我跟进问了一些具体的问题,他都没有能答出来,只能用一些软件设计的大道理来“招架”,所以我只能认为他软件设计不具备实际的工作能力了。
图5.1在前面中出现,是因为我要说明什么是N层架构,这个图在前文中是没有问题的。但如果用这个图来表示一个具体项目的架构设计,那么就是等于“废话”!如果设计文档中仅仅只有类似图5.1的通用设计图,这个文档可以扔掉了。
但凡事有例外,某公司的设计文档果然就是这个样子的,你会发现一个很“神奇”的情况:只有将项目的名字和相关的背景描述改一下,这个设计文档马上可以成为另外一个项目的设计文档!而项目组们对这个事情乐此不彼,他们非常“欣赏”这样的设计文档。你会觉得很奇怪,难道这个项目小组是不干实事,喜欢干这些没用的事情?后来我才发现其中奥妙:因为该公司的过程规定项目必须写设计文档,QA经常来检查,项目组为了应付这个检查,就用这个最节省工作量的办法来应付过去。了解真相后,真的是让人哭笑不得!
分层设计确实是很多系统的设计思路,但在一个具体系统中表示 分层设计时就需要表达得更加具体,太抽象就变成“放之四海而皆准”了,我们要避免“一招走天下”。

案例2:部署图表示的系统架构

图5.2 部署图表示的系统架构
为了避免“放之四海而皆准”的问题,我们要求要用部署图表示系统架构。最开始还挺有新鲜感的,但慢慢我们发现画出来的图与图5.2类似。我们做的系统大部分是“网页+数据库”类型的,系统就只有三种机器,分别是:客户端、Web服务器和数据库服务器,而Web服务器和数据库服务器还往往是同一台服务器呢。于是有同事提出:部署图画架构设计一点用处都没有,因为都是一个鬼样,大同小异而已。确实如如果每个项目的架构设计图和图5.2差不多,那么又犯了“放之四海而皆准”这个毛病!

架构设计应该如何做呢?下面我们通 过实际案例来体会


5.4 架构设计是考虑“全部需求”后做出来的

我们仍然用考勤系统为案例,不过和前面的要求不同,需求有所调整。

先看看项目背景
某公司员工人数约100人,领导想做一个系统对员工的外出及请假进行管理,具体需求见用例图(见后文)。
假定我们不太需要考虑进度、成本的限制,我们的目标是做出一个高性价比的设计。

现在请看需求

图5.3 外出请假管理系统的用例图
图中红色虚线框框框住的内容是比较麻烦的,对软件设计提出了更高的要求。
架构设计需要考虑全部需求,我们要从这些需求当中发现一些设计的关注点,你发现了哪些呢?

发现设计关注点

我将通过两个图来分析设计关注点,先看第一个图:

图5.4 设计关注点1
我们需要思考全部需求, 对不清楚不具体的需求要进一步提问题,思考这些需求的技术解决方案等等。
此图列出了两个关注点,红色边框框住的部分是第1个关注点,标记上“1”这个符号;而蓝色边框框住的部是第2个关注点,标记上"2"这个符号。

请看第二个图:

图5.5 设计关注点2
此图展示了第3、4个关注点。

实际上设计关注点可能不止4个;也有可能少于4个,因为你很牛的话,有些技术点已经驾轻就熟了,对于你来说就不是问题。上述两个图展示了前文提到的 “优秀的设计从分析需求开始”的思路,接下来我们需要进行初步架构设计并且逐步细化这个设计。



5.5 逐步拆解架构设计

需求驱动设计
有这样的一句话:不以结婚为目的的谈恋爱是耍流氓!
这句话与软件设计有什么关系呢?很有关系呢!因为有另外这样的一句话: 不以解决需求为目的软件设计就是耍流氓
所以如果不想被人家说你耍流氓,你需要了解需求,需要“需求驱动”地思考设计问题。

前文我们从需求中发现了 四个设计点,一起来回顾一下:
1)用例图中提到,员工可以通过移动设备提出请假或外出申请,领导可以及时收到审批的提醒。那么我们应该如何设计“即时了解”和“及时收到提醒”呢?解决方案可能有:短信提醒、邮件提醒、或者两者同时提醒。
2)需求中要求员工可以通过移动设备提出申请,领导也可以通过移动设备完成审批?我们要思考,为什么需要移动设备完成这些工作呢?什么情况下才需要通过移动设备完成这些工作呢?我们的解决方案是怎样呢?通过短信、手机上网,还是通过手机的APP来搞定?
3)请假申请和审批流程,跟流程相关的都可以扯到“工作流”。 工作流可以是一个很“恐怖”的话题,你打算做一个"死"的工作流,“半死不活”的工作流,还是“全活”的工作流呢?你打算从零开始做,还是买一个工作流引擎呢?
4)权限要做成重用已经是有一定难度的,同时还需要考虑与工作流的结合,还要考虑工作流也可以做成重用,难度很高啊!那到底要不要考虑做成重用,并且权限和工作流能结合起来呢?

补充说明一下 工作流
1)死的工作流:就是代码写死的(hard code),数据库设计也是死的,流程或表单有任何变化,都可能需要改代码和数据库设计。
2)半死不活的工作流:部分地方写死,部分地方是灵活的,能适应部分需求变化。
3)全活的工作流:代码和数据库设计等都是灵活的,能基本适应流程及表单的变化,不需要修改代码或数据库设计,只要配置一下就可以搞定。
没有任何工作流技术积累的情况下,要做到“全活的工作流”是很高难度的,一般不要在当前项目中就定下这样的设计目标,基本是实现不了的。可以分阶段来做,先写“死”,然后“半死不活”,最后才追求“全活”。

步架构设计(第一层拆解)
我们再次回顾一下,什么才是优秀的设计?
我在前文中提到,一个优秀的设计应该具备以下特点:

1)优秀的设计都是需求驱动的,不熟悉需求就做出来的设计是不靠谱的;
2)优秀的设计应该是当前团队能理解能实现的,太超前的设计项目团队做不出来,这个设计只能是摆设;
3)优秀的设计应充分考虑当前各种限制条件,适当做出平衡,能保证达成项目的目标:
4)优秀的设计能尽量降低项目的整体工作量,让整个项目更加可控。

我们尝试一下,尽量按上述标准来完成这个设计吧!


我打算用 .net(开发语言采用 C#) 及 SQLServer 来开发这个系统。
你可能会问,为什么你选择这个开发语言和数据库?这些不是需要论证,需要做方案选择的吗?
我们不是搞理论或学术研究,一个真实项目的情况是这样的:你接手项目时合同已经签下来,合同中会规定用什么技术框架的,包括开发语言与数据库,一般不会不定下来的。而定下来的技术框架,一般就是你们公司最熟悉的那种,而你接手这个项目,一般是熟悉这个技术框架的。公司不会这么傻,选一个自己公司一点都不熟悉的技术框架来完成项目,客户更加不会这么傻选一个不懂这个技术架构的软件公司,你的上司也不会这么傻找不熟悉这个技术架构的你来负责这个项目的设计。
一个系统到底用.net好一点,java好一点,PHP好一点?这些其实没有定论的,一般来说就是你熟悉哪个就用哪个!哪个你最有经验最有成功案例就用哪个!针对具体一个项目做架构设计时,不能脱离具体的技术框架,要先确定 你的开发语言、数据库种类等。架构设计要从物理设计的深度来思考,而不能仅仅是理论设计或者是逻辑上的设计,否则又会犯了太空洞的毛病(即“放之四海而皆准”的毛病)。

以下是初步的架构设计,这个设计并不是怎样“惊天地泣鬼神”,仅仅是我觉得我们能做到的也能应对需求的一个设计。


图5.6 初步的架构设计

图中标记出来的1、2、3、4,分别对应对前面的设计关注点1、2、3、4。此图对设计关注点1、2考虑得稍微具体一点,而对于设计关注点3、4仅仅是一个初步的考虑,因为当时我们工作流的技术积累还比较初级。
需要特别说明的:请留意“智能手机”这个客户端,图中写的是操作系统用WindowsMoble,这是一个以前的设计,在现在看来是不合适的,现在用这种操作系统的手机几乎不存在了。需求中提到要求使用移动设备完成相关工作,那么我们就需要思考是什么移动设备呢?移动设备上需要什么操作系统?需要安装什么软件等等?这些我们都需要考虑。

小结一下进行初步架构设计的要点:
1)我们的系统大部分会涉及到多个客户端及服务器,我们需要思考我们的系统需要怎样的客户端及服务器,思考这些设备上面需要安装怎样的操作系统、平台、软件等,思考这些设备需要怎样的硬件配置,如CPU、内存、硬盘大小等等。
2)我们需要思考这些 客户端及服务器之间的物理联系方式,例如:是局域网方式、互联网,还是两者都支持?是HTTP或是HTTPS?等等。
3)这些设备上我们需要开发什么软件、数据库等?例如:图5.6中需要我们需要开发的东西有:Web Application、工作流定义用的客户端软件、三个数据库。架构设计其实就是划分系统的各部分及各部分的关系,这些内容其实就是我们整个系统的第一次的各部分的划分,而各部分的关系我们可以通过图6.6大致可以了解。

继续深入拆解(第二层拆解)
图5.6已经从硬件配置、软件各部分的划分、数据库的规划等方面描述了本系统的初步架构,当然这个架构还是太粗了,我们还需要继续深入思考,请看下图:

图5.7 架构设计的进一步思考

这个系统至少有5个需要我们开发的部分,每一个部分都需要更进一步深化设计,下面我们以Web Application为例子,继续深入设计!请看下图:


图5.8 Web Application的设计

我们规划 Web Application 的内部架构时,除了考虑内部各部分之间的关系,也需要考虑内部所划分出来的各部分,有哪些是需要和外部交互的?图5.6中表示的各部分关系还比较粗,我们还需要继续细化,请看下图:


图5.9 系统各部分的关系

当我们逐步细化设计的时候,我们很可能会发现之前初步架构设计不合理的或遗漏的地方等等,留意图5.9中红色的部分,这是之前没有画进去的内容。这个图已经更进一步细化设计了,但我们仍然有很多问题未解决,请看下图:


图5.10 更多的更具体的设计问题

图5.10与图5.9的区别就是多了黄色的部分,请思考这三个问题:
1)权限设置的UI如何考虑?
用户管理、权限管理的UI可考虑设计成可重用的。
界面可以是独立的,也可以“嵌入”到别的系统中。
2)工作流如何设计?
还需要对工作流进行进一步的抽象。
考虑清楚工作流的对外接口。
考虑清楚数据库设计。
3)图形定义客户端软件如何设计?
图形平台自主开发,还是利用第三方的?
数据如何保存到DB中?
除了上述这些问题和思考,还会有更多的其他问题,软件设计是充满挑战的工作!

设计初期的问题可能比较朦胧比较大,但随着设计的深入,问题会越来越多,问题也会越来越具体。有时候你会觉得怎么越深入设计,发现的问题越多,这是正常现象,而且是好事!如果没有发现问题,这往往不是真的没有问题了,而是我们不具备发现问题的能力了,这是相当可怕的,要小心留意不可轻敌噢!

图5.6后我们连续进行了多步的设计拆解,这里小结一下:
1)系统需要开发什么软件和数据库等,这些是第一次对系统各部分的拆分,姑且这叫”第一层的拆解“,接下来需要继续拆解。
2)继续拆解时可参考分层架构,但需要拆分得更加具体,不要犯”放之四海而皆准“的毛病。这个层次的拆解,姑且叫“第二层的拆解”。
3)除了规划好内部各部分的关系,还需要规划内部的各部分与外部之间的关系。
4)在拆解的过程中,问题会越来越多,也会越来越细,这是正常现象,也是好现象。
5)拆解过程中也可能会发现之前初步架构设计中不合理或遗漏的地方,请马上调整;有时候甚至会发现之前的设计完全不对,那么就要有勇气推翻重做。
6)“第二层的的拆解”结果有可能是组件(Component)、代码包、某个分层等等,可能是“物理分拆”也可能是“逻辑分拆”。那么“第二层的拆解”要多细才合适呢?其实很难有固定的标准,给一个简单标准作为参考:如果再拆解下去下一步的拆解就到类了,那么就可以认为目前的拆解粒度比较合适了。细化到类的拆解,可以在模块设计(详细设计)中再进一步考虑。

说明一下“物理分拆”和“逻辑分拆”:
物理分拆:物理分拆就是物理上是独立的部分,有可能是exe、dll、数据库文件等。图6.6中将系统分拆为5部分,分别是Web Application、流程定义用的客户端软件以及三个数据库,这就是物理分拆;我们对Web Applicationi继续分拆时,图6.8中的日历控件是物理分拆,这个控件将通过二进制的方式供程序其他部分调用,而这个控件将来也可以供其他系统使用。
逻辑分拆:代码包、某个分层这些往往是逻辑分拆,物理上它们不会编译成单独的一部分,而是被整体编译进软件当中。

“第二层拆解”的目的除了更加方便我们设计出系统,另外一个重要目的就是做系统的重用设计。如果是“物理分拆”,就可以做到二进制重用;如果是“逻辑分拆”,那么只能做到源代码重用。这些重用不仅仅为当前软件服务,还可以为将来及其他软件服务。


5.6 分布式系统与单机系统的架构设计

分布式系统可能有很多定义,有些资料可能也说得比较炫,文章这里提出这个说法不是用来“抛书包”的,这里也顺便说明一下:本文中提出的一些概念(例如:第一层拆解、第二层拆解、物理分拆、逻辑分拆)是为了更加方便说明问题而已,大家没有必要去互联网上搜索这些名词的定义。
我们开发的东西只需要安装在一台电脑上,这个软件就能工作,这就是单机软件,例如Office软件、Photoshop软件等;但分布式系统往往需要我们在多台设备上部署,各部分需要联调后,整个系统才能正常工作。
文中用到的案例是分布式系统,分布式系统如何做架构设计,相信你已经有一些体会了。单机系统的架构设计看上去似乎更简单一点,因为它不需要做“第一层拆解”,直接就是“第二层拆解”。其实不一定的,因为单机系统的“第二层拆解”往往是很复杂的,单机系统往往有特殊的高科技的算法、有独特数据存储格式等等,你可以设想一下,你能完成Office的架构设计吗?还有Photoshop的架构设计?


5.7 架构设计小结

架构设计是高难度、高技术含量的活,我觉得很难写出一本秘籍,你看了后就能应对大部分软件的架构设计。如果我们不精通业务,不精通技术,没有丰富的设计经验,很多设计我们将会束手无策。

小结一下分布式系统的架构设计要点,单机系统也可以参考:
1)我们的系统大部分会涉及到多个客户端及服务器,我们需要思考我们的系统需要怎样的客户端及服务器,思考这些设备上面需要安装怎样的操作系统、平台、软件等,思考这些设备需要怎样的硬件配置,如CPU、内存、硬盘大小等等。
2)我们需要思考这些客户端及服务器之间的物理联系方式,例如:是局域网方式、互联网,还是两者都支持?是HTTP或是HTTPS?等等。
4)思考系统需要开发什么软件和数据库等,这些是第一次对系统各部分的拆分,姑且这叫”第一层的拆解“。
5)继续拆解时可参考分层架构,但需要拆分得更加具体,不要犯”放之四海而皆准“的毛病。这个层次的拆解,姑且叫“第二层的拆解”。
6)除了规划好内部各部分的关系,还需要规划内部的各部分与外部之间的关系。
7)在拆解的过程中,问题会越来越多,也会越来越细,这是正常现象,也是好现象。
8)拆解过程中也可能会发现之前初步架构设计中不合理或遗漏的地方,请马上调整;有时候甚至会发现之前的设计完全不对,那么就要有勇气推翻重做。
9)“第二层的的拆解”结果有可能是组件(Component)、代码包、某个分层等等,可能是“物理分拆”也可能是“逻辑分拆”。那么“第二层的拆解”要多细才合适呢?其实很难有固定的标准,给一个简单标准作为参考:如果再拆解下去下一步的拆解就到类了,那么就可以认为目前的拆解粒度比较合适了。细化到类的拆解,可以在模块设计(详细设计)中再进一步考虑。






6)打造系统的底蕴——数据库设计

6.1 数据库结构变更可大可小

数据库字段的微调,比方说增加一个字段、修改一个字段等等,是很常见的事情。当然这样的事情经常发生的话,也是挺让人厌烦的,所以我们可能会在数据库中增加一些保留字段。
以前参考前辈的数据库设计时,经常会发现一些“保留字段”,于是自己也去模仿一下,后来发现好像没有什么用。比方说:当需要增加一个字符型的字段时,我会去找一个字符型的保留字段,将原来字段的名字由“保留1”改为合适的名字;当需要增加一个数字型的字段时,去找一个数字型的保留字段,将原来字段的名字由“保留X”改为“XXX”。这样的做法,和增加一个字段有什么区别呢?还不如取消保留字段,需要时再添加字段就是了。
数据库字段的变更还算是小变化,虽然会带来数据操作层、业务层、表现层代码的修改,也可能需要“升级”旧数据,但这些都算是“小动作”,还不算“很可怕”,“最可怕”的可能是数据表或表关系上的变化,例如:原来的表设计不合理,需要将一个表拆分为两个或以上的表;需求发生变化,需要增加更多表格;原来的表关系不对需要修改等等,这些变化将会导致程序的大范围修改。
正因为数据库的结构变化可大可小,可能遇到相关问题的时候我们会采取“将就”的策略,仅仅是对数据库进行修修补补,不太敢从根本上改造数据库,以致雪球越滚越大,最终有一天会发现数据库结构实在无法适应需求了,但工期压力又超级巨大,这时只能祝你好运了!


6.2 数据库结构变更的源头是什么?

数据库变更的原因可能有:
1)客户的需求并没有发生什么变化,而是我们前期的需求分析不到位,或者是我们前期对数据库设计不重视,导致数据库设计不合理。
2)客户的业务发生变化,以致数据库也需要调整设计。
无论是哪种情况,其实都是业务概念驱动数据库设计!请看前文出现过的一个图:


图6.1 业务概念驱动数据库设计

此图是前文说明“由底而上”的设计思路时的一个图,现在我们再重新理解一下:
1)“需求分析”活动有三种工作产物:业务概念图、业务流程图和用例/用户故事。
2)“业务概念图”是“设计数据库”活动的“输入”,也就是“业务概念图”是数据库设计的重要依据。

那什么是“业务概念”呢?下面我们通过实例来理解“业务概念模型驱动数据库设计”。


6.3 案例:学生选课系统——业务概念模型驱动数据库设计

案例:学生选课系统的业务建模
某学生选课系统部分需求如下:
1)学生基本信息:学号、姓名、年龄、所在学院、学院地址、学院联系电话。
2)课程基本信息:名称、学分、类别(必修、限选、任选)。
3)学生可以读多门课程,每门课程都有相应的成绩。
你觉得仅根据上述信息,是不是可以进行数据库设计了?建议你先根据上述信息思考一下数据库设计,完成后再继续阅读后文,这样效果更好。

实际工作中因为工期压力大,我们可能不会稍微停留一下思考一下这些需求,而是直接就是数据库设计。这样做有相当大的风险,很可能会导致数据库设计不符合“三大范式”的要求的,导致一些问题,例如:1)该拆分的表没有拆分,表关系不合适;2)字段设计不合适;3)数据冗余,容易出现不一致等等。如果我们能先进行业务建模,可以帮助我们避免这些问题。

下图是对上述需求的业务概念建模分析:


图6.2 选课系统的业务概念建模

我通常用UML的类图来整理业务概念模型,简介一下这个图的基本语法:
1)图中的一个个矩形就是类,这个图有四个类:学生、学院、课程、成绩;
2)学生与学院之间,学生与课程之间有实线相连,表示它们”有关系“;
3)学生与学院之间的关系是 ”* 对 1“,表示多个学生对应1个学院;
4)学生与课程之间的关系是 ”* 对 *“,表示多个学生对应多个课程;
5)成绩这个类有一条虚线连到学生与课程之间的实线,这个成绩类叫关联类,这可能是比较难以理解的,它表示的是学生与课程之间的关系的约束,这个”成绩“你可以理解为:每个学生在每个课程中的成绩。

补充说明一下,严格来说业务建模有两种:业务结构建模和业务行为建模。上述案例其实做的是“业务结构建模”,主要是对数据结构进行分析;“业务行为建模”主要是对流程、过程等进行分析,图7.1中“需求分析”的其中一个工作产品是“业务流程图”,这个“业务流程图”就是行为建模的产品。后续文章会为大家分享更多行为建模的内容。

根据这个业务概念建模,我们可以进行以下的数据库设计,我们将通过三个图来说明。


图6.3 选课系统的数据库设计1
右上方是业务建模的小图,方便大家对照来看,图7.3 展示了”学生类“与”学院类“对应的数据库设计。


图6.4 选课系统的数据库设计2
此图展示了”课程类“和”成绩类“所对应的数据库设计,请重点看”成绩类“的数据库设计。

下图是上述两个图的汇总:

图6.5 选课系统的数据库设计3

这个数据库设计一共有4个数据表,请对照图7.2来思考一下,业务概念建模是如何驱动数据库设计的。
如果忽略了”业务概念建模“这一步,我们的数据库设计可能会:
1)没有能拆分出学生表、学院表、课程表;
2)没有能拆分及设计出合适的成绩表。

如果你曾经用过E-R图(实体关系图),或者用过 Power Design 软件设计过数据库,你会发现上述文章的内容也就是那么一回事!
用类图分析业务概念,确实与E-R图很类似,道理也是共通的,但是还是有一些区别的:
1)E-R 图一般是直接面向数据库设计的,实体之间的关系一般就是1对1、1对多,而多对多的关系通过两个1对多来间接实现;
2)类图也能表示上述关系,但类图可以表达更丰富的内容,比如:继承(泛化)、包含(聚合、组合)、依赖、关联类等等。
也就是说用类图分析业务概念模型,能达到更广和更深的效果,当然这是我个人的体会,仅供参考。

如果你一直用 E-R 图用得好好,也没有必要非要转成类图来分析。无论是类图、 E-R 图,还是其他的什么图或工具,我们的目的都是为了更好的理解需求,梳理业务和整理出合适的业务概念模型,为数据库设计打好基础。

7.4 考勤系统的业务建模及数据库设计

学生选课系统这个案例比较简单,主要是帮助大家理解”业务概念模型驱动数据库设计“。接下来我们继续用”考勤系统“这个例子为你分享,我的主要目的有:
1)对考勤系统进行行为建模;
2)通过另外一个例子再次体会如何用类图分析业务概念模型;
3)根据业务概念模型,同时考虑到我们的现实情况,我们要做一个“老土”的数据库设计;
4)深挖业务概念模型,做一个“高端大气”的数据库设计。
本小节为你分享第1、2、3点。

这个考勤系统的需求请参考前面的文章,如果忘记了一定要重新看看噢!
你可以会发现,前面的文章没有详细描述请假(外出)的审批流程,下面我们通过一个图来看看这个流程吧,这个图就是业务行为建模的其中一个结果。


图6.6 请假审批流程活动图

了解这个流程后,我们将会对业务概念模型有更加清晰的认识,下面直接上两个业务建模的图:


图7.7 考勤系统的业务概念建模1


图7.8 考勤系统的业务概念建模2

上面两个图结合一起看才是完整的业务建模,因为一张图太大可能会显示不下,或者显示出来不好看,所以才拆分成两张图。

根据上述业务建模,如何来设计数据库呢?如果照搬学生考勤系统的做法,那么一个类至少要对应一个数据表,这样设计的话似乎有点麻烦,后续写起代码来也可能挺麻烦的。我们要思考这个系统的主要需求是什么?这个系统主要是围绕请假(外出)的审批流程进行的,其实就是一个简单的工作流,我们要解决提出申请以及多个层次的审批问题。现实项目中进度压力是很大的,也会受制于各种限制条件,所以能解决需要当中主要矛盾的设计就是一个好设计,所以我有这样的一个老土的设计,能满足需求,实现起来也比较简单。请看下面的两个图,节选了部分的数据库设计。


图6.9 考勤系统的数据库设计1


图6.10 考勤系统的数据库设计2

这个设计相当老土,本来应该拆分为多张表的全部弄到一张表去:
1)当提出请假申请时,请假申请表就多了一条记录,这条记录审批相关的字段全部都是空的;
2)当去到某个审批环节时,该申请记录只需要更新相应的字段就行了。

这个程序的代码写起来也比较简单,例如:表现层不需要针对不同的流程环节设计不同的界面,直接可以通过一个界面搞定,当然还要写一堆 If Else 或 Switch Case。表现层的代码思路如下图:

6.11 考勤系统的表现层代码思路

当员工提出请假申请时,他只能看到1这部分的内容,2、3、4部分隐藏;当部门经理审批申请时,1部分只读,2部分可编辑,3、4部分隐藏,副总和总经理审批时也进行类似的处理。

数据库设计不能单纯仅仅从数据库的角度来考虑,还需要整体平衡这个项目的工作量,一般来说能解决需求当中的主要矛盾,能让整个开发工作量降下来,并且是项目团队有能力做到的设计,这样的数据库设计及软件设计才是好的设计。

考勤系统的业务建模及数据库设计,也说明了这样的最佳实践:
1)业务结构建模和行为建模是很有必要的,业务建模这一步可以多深入一些,不要因为项目进度紧而压缩你的时间,这里的时间投入所带来的回报是超值的;
2)业务建模让我们对需求的理解更深,让我们的数据库设计及软件设计”进可攻退可守“;
3)遇到进度压力及各种限制条件时,你不一定非要照这个业务模型来设计你的数据库和代码,你可以退一步,用一个”老土“的数据库设计及程序设计来解决问题;
4)你也可以采取更加进取的设计策略,这点下一小节为你分享。


6.5 业务建模更上一层楼,打造更具弹性的数据库设计

本小节为你分享前文提到的第 4 个目标:深挖业务概念模型,做一个“高端大气”的数据库设计。但这个目标实在太“伟大”了,这里能仅为你分享开始的一部分,后续有机会我再发文章分享更多内容。

我们有更多的思考:如果请假(外出)审批流程改变了,例如增加了审批环节,怎么办?按照前面的“老土”设计的话就麻烦了,我们需要增加“请假申请表”的字段,而表现层的代码也需要修改,需要更多的If Else。
当然我们可能还有一个更好的处理办法,就是认为这是需求变更,对客户说:no money no talk(没有钱没商量)。只要前期我们的业务分析足够到位,将流程图、业务概念图等全部画出来,并且跟客户确认好了,客户就不能赖账了,增加审批环节,这明显就是需求变更嘛,是需要工作量,需要付钱滴!但是我们为什么不能将程序做得更有弹性呢?为什么不能做一个“全活”的工作流呢?这样我们的软件将会更有竞争力,帮助我们赚到更多的钱。

前文的文章提到的工作流,分为三种层次:
1)死的工作流:就是代码写死的(hard code),数据库设计也是死的,流程或表单有任何变化,都可能需要改代码和数据库设计。
2)半死不活的工作流:部分地方写死,部分地方是灵活的,能适应部分需求变化。
3)全活的工作流:代码和数据库设计等都是灵活的,能基本适应流程及表单的变化,不需要修改代码或数据库设计,只要配置一下就可以搞定。
前面这个老土的设计,是属于那种一种层次呢?
我都不好意思说了了,这是“死的工作流”,弹性最差的!流程稍微改变,就要到处修改,包括修改数据库设计和代码。

下面我们尝试一下做“活的工作流”,我们需要再进一步分析业务模型,找出流程的规律,针对规律来设计数据库和软件!


图6.12 考勤系统业务概念模型的深入挖掘

上图红色虚线框框里面的内容就是规律,而且其他部分可以看成是这种规律的一个“实例”。
这个图揭示了这样的规律:
1)从提出申请开始,后续的审批其实就是一个”审批链”;
2)“申请”对应一个“首次审批”,“首次审批”后续是“下一个审批”;
3)对应某一个“审批”来说,如果它不是“首次审批”,它对应一个“上一个审批”。
如果数据库及程序能针对这样的规律进行设计,那么只要是符合这个规律的情况,系统都可以适应,这样就不怕审批流程的变化了!

图7.12 可能有点难度,如果没有应用类图分析业务的经验,会更加难理解此图,但这仅仅是挑战的开始!当我们需要打造更具弹性的系统的时候,我们面临两大挑战:
1)透视需求发现需求本质的能力,建立更深层次的业务模型;
2)根据第1)点的业务模型,设计出相应的数据库设计及软件设计。
这两大挑战都是难度很高的,图 7.12 仅仅是业务模型进一步深挖的开始,打造“活的工作流”难度是很大的,将来有机会再分享更多文章。


6.6 数据库设计小结

数据库设计的好坏决定了系统的底蕴,无论是“老土”的设计还是“高端大气”的设计,都是为项目的目标服务的。
一般来说我们应该达到以下基本要求:
1)意识上要重视数据库设计,数据库设计上的时间投资是超值的;
2)良好的业务建模(包括结构建模和行为建模)是良好数据库设计的基础,并且可以让你在后续工作中“进可攻退可守”;
3)在业务概念模型的基础上搭建数据库,你可以采用类似学生选课系统的数据库设计方法(业务实体类与数据表一一对应),也可以采用考勤系统的“老土”设计方法(合并业务实体类到一个表中)。
当条件成熟时,我们可以考虑进一步提升我们的业务深挖能力及弹性设计的能力,让我们的软件更好卖,让我们可以赚取更高的薪金!





7)细节决定成败——详细设计

7.1 什么是详细设计?

当我们需要考虑类、类的内部细节、类之间的关系时,这时我们已经开始做详细设计了。详细设计不一定是一份文档,也不一定是Word文档,详细设计也不一定叫“详细设计”,有时候“编码就是设计”也是未尝不可的。下面是我的一些最佳实践:

实践一:模块设计
我早期的一些项目会写一份详细设计文档,但后来的项目我会将详细设计文档分拆为N份模块设计文档了,这样做的两大好处是:
1)一份详细设计文档太大,不利于阅读,不利于指导编码工作,分拆后就好多了;
2)N个模块设计的任务可以分派给不同的软件设计师(或程序员)来负责。

实践二:代码就是设计
有时候我会“偷懒”,我觉得没有必要再写什么设计文档,直接在开发工具中定义好类,写好类的公开接口,写好注释等等,这时我其实就是在做详细设计的工作,我将代码框架写好后,才写具体的实现代码。这种工作模式其实就是将详细设计与编码实现融合在一起了,效果和效率更好!当然不是说不再需要写Word文档格式的详细设计了,对应比较复杂的详细设计,一般还是需要通过另外的文档来描述一下比较好。
但可能会有一种比较详见的“特殊”情况:你可能会遇到开发人员死活写不出Word文档格式的详细设计,你和他沟通多次后,他还是写不出有质量的Word文档格式的详细设计,这时你不如让他直接写代码,先写个框架看看,然后你通过评审代码来修正他的设计。

实践三:Demo就是设计
设计逻辑复杂时,可能需要文档来应对,但文档毕竟是纸上谈兵,可能最切实的办法是做一个 Demo 实现你的算法和设计思路。只要 Demo 是 Work 的,就可以将这个 Demo 的代码重用到实际的项目中。
举一个例子:曾经某项目中需要写代码解决判断一个点是否在多边形内,算法有点麻烦,光写文档说算法没有实质的价值,于是我用了半天时间写了实现的代码和测试的代码,将这个Demo提交给项目组。

实践四:“无”详细设计
无详细设计的意思不是真的不考虑详细设计了,而是对于这种情况我们已经驾轻就熟了,几乎是闭着眼睛都会做了,所以我们就“无”详细设计直接编码了。


7.2 详细设计的基础

我曾经评审过一份设计文档,该文档内容详细、思路清晰,清楚描述了某些技术环节的实现办法,而且实现办法都是可行和有效的,这个文档可以算是一份比较好的详细设计文档了。但可惜的是,整个项目只有这样的一份设计文档,从全局来看这个文档只解决了局部问题,缺失了一些核心内容:
1)没有架构设计的的内容;
2)没有数据库设计的内容;
3)系统的需求很复杂,大部分的需求没有对应的设计考虑。

前面的文章曾提到,我做过的项目一般至少会有一份概要设计文档,详细设计文档不一定是必须的。详细设计固然重要,但针对整个系统的全面考虑更加重要,详细设计之前应该具备以下条件:
1)应针对全部需求(包括功能性和非功能性的需求),系统需要有整体上的考虑,也就是前文提到的架构设计。
详细设计需要考虑类、类的内部细节、类之间接口等,这些是需要符合系统的总体架构和分层架构的。
2)应有数据库设计。
如果没有数据库设计,建筑在数据库之上的代码是很难写的。当然如果你是用“由中间到上下”的设计方法的话(什么是“由中间到上下”?请参考前面的文章),数据库设计没有,只要有中间层的建模的话,表现层和逻辑层的代码还是可以写的,但数据库操作层的代码还是依赖于数据库设计的。
3)部分情况下,还应该有部分或全部的用户体验设计(用户体验设计下一篇会分享)。
用户体验设计主要考虑的是软件的表现层,最能充分体验“由顶而下”的设计思路,将会直接影响具体的代码实现。

一般情况下我们应该在架构设计和数据库设计的基础上进行详细设计,否则很可能会让我们仅仅关注了局部的问题,而没有抓住其他更加重要的问题和全局的问题。如果没有架构设计和数据库设计,直接详细设计是不是一定不可行呢?有以下的一些特殊情况(不限于此噢):
1)如果果你的情况是在原有系统上升级改造,系统原有的架构和数据库设计基本不变,那么直接进行详细设计是合适的做法;
2)有时候有些局部问题虽然很“局部”但又相当特殊或重要,哪怕没有来得及完成架构设计和数据库设计,也可以先进行详细设计的。
后文我们先从正常思路介绍详细设计,也就是先有架构设计和数据库设计再有详细设计,然后再分享一些上面第2)点的情况。


7.3 详细设计是架构设计的延续

前文的架构设计提到我们要对系统进行两个层次的拆解,分别是:
第一层拆解:思考系统需要开发什么软件和数据库等;
第二层拆解:考虑组件(Component)、代码包、某个分层等等,可能是“物理分拆”也可能是“逻辑分拆”。
不太记得或者看不懂的朋友,请先看看前面的文章啦。
而详细设计其实就是:
第三层拆解:进一步细化出类、类对外接口、类的内部细节等。

通常我会用UML的顺序图(Sequence Diagram)来表达“第三层拆解”,请看一个简单一点的图,了解一下顺序图。


图7.1 详细设计-顺序图1

我们通过这个图了解两个事情:
1)顺序图的基本语法;
2)顺序图如何表达详细设计。

这个图表示的是用户在某个查询页面输入查询内容、点击查询按钮等这些用户交互及背后的程序设计。通常顺序图最左边画的是用户,仅次之是软件的表现层的某个页面(界面),用户与表现层的之间的交互,会导致表现层后面的类的一系列动作。这个图还算比较简单,请看下面这个我在N年前完成的某项目中的其中一个顺序图:


图7.2 详细设计-顺序图2

架构设计需要考虑全部需求后设计出来,也就是说”全部需“求驱动架构设计,当然某些特殊的需求点需要特别关照;数据库设计主要是业务概念模型驱动的,业务建模及进一步提炼可以帮助我们设计出更有弹性的设计。那详细设计是不是仍然需要”需求驱动“呢?这是必须的!
我们可能用用例(UseCase)、用户故事(User Story)或者是功能点等方法表示需求,不管怎样的表示办法,最终都会拆解为一条条比较细的需求。每一条需求具体如何实现呢?顺序图就是表达这个实现方法的好工具!图7.1 和 图7.2 分别说明的都是某个需求点的实现方法,图8.1 是查询用例的详细设计, 图7.2 是修改材料设备信息的详细设计。一个系统的详细设计,就可以用类似图7.1和图7.2的图逐一表示出来。

我们通过下图再充分理解一下需求如何驱动详细设计:

图7.3 详细设计-顺序图3

上图红色框框部分的内容是需求,用户和系统界面之间的交互设计是对需求的进一步细化;蓝色框框部分是在需求驱动下的程序实现,此图实现部分比较简单,大部分的程序实现逻辑都会比上图复杂,会涉及到逻辑层、数据操作层还有一些共用模块之间的调用等等。详细设计除了要需求驱动,同时也要需要符合架构设计,代码也需要基于已有的数据库设计,换句话说就是详细设计是需求、架构设计及数据库设计三者同时驱动的。

本小节所列举的详细设计的例子都是MIS类型系统的例子,基本上围绕数据库的增删改查进行,设计难度其实并不是很大。前面已经提到,如果对于已经很熟悉的情况,你没有必要再用顺序图来画一次了,直接可以”无”详细设计;但如果你的团队成员还不是很熟悉数据库的增删改查,或者实现逻辑比较复杂,这样就很有必要进行详细设计了。

本小节的例子比较“常规”,老鸟可能觉得没啥难度,下小节的难度将会增加。


7.4  详细设计是解决局部问题的良方

前面提到,有些局部问题虽然很“局部”但又相当特殊或重要,哪怕没有来得及完成架构设计和数据库设计,也是需要先进行详细设计的。
举三个例子:

案例1:针对网络负载平衡的特殊考虑
某客户的Web服务器采用网络负载平衡,有两台Web服务器,这与我们惯常的一台Web服务器场景很不一样。我们打算使用公司的框架来开发这个系统,但这个框架的其中一个地方很可能会出问题。框架使用了静态变量用来记录数据库中ID的最大值,当增加一条记录时就 ID_Max = ID_Max + 1,将新的 ID_Max 作为新增加记录的ID。这样在两台Web服务的场景下,就会有两个静态的 ID_Max,两边都很可能会出现不准确的情况,导致数据插入到数据库中时出错。本身这个修改并不算复杂,但我们需要同时考虑兼容框架,因为这个框架是同时支持 SQLServer 和 Oracle 数据库的,我们的首席设计师很厉害,在框架层面解决了这个问题,不仅可以继续保持框架的兼容性,还扩大了框架的适应面。

案例2:点是否在多边形内的求解
这个几何问题是由业务问题转化而已来的,这是一个某移动通讯公司的系统,先简单介绍一下业务。
我们的手机是通过基站进行通讯的,如果附近没有基站,就会出现手机没有信号的情况。我们所居住的城市当中,一般会有上百成千的基站,保证我们通讯畅通。基站与基站之间形成的通讯网络,会划分为以基站为中心的多个“多边形”,形成一个好像蜂窝的样子,这就是我们经常听说的蜂窝网络。但有可能会出现某个地方打电话有问题的情况,这个出问题的地“点”位于哪个“多边形”呢,系统需要通过点的坐标找到这个点在哪个多边形范围内,进一步定位到是哪个基站可能出问题。 
上述就是原始的业务背景,我们将这个需求演化为一个几何问题,当时我参考了“放射线”的算法,直接通过“Demo法”来完成这个设计。前文的”实践3:Demo就是设计“中提到的例子,就是这个例子了!

案例3:让程序支持 Undo 和 Redo
如果要求你的系统支持 Undo 和 Redo,不知道你会如何考虑呢?支持 Undo 和 Redo 是非常酷的,但难度是相当之高的,你会先完成架构设计和数据库设计才考虑吗?23设计模式中的命令模式可以帮助我们,但命令模式仅仅是给出了解决问题的框架而已,你还需要演化为更实际的内容,否则又犯了”放之四海而皆准“的毛病了。命令模式很有难度,但很有意思和很有用,我们这里不详解命令模式,大家可以参考我的设计模式方面的文章。
这里举这个例子是想说明:某些需求看上去好像是仅仅很小的一个点的要求,有可能影响面很大,你可能需要先针对这个点去思考详细的实现办法,然后才能帮助你想清楚架构设计及数据库设计。

小结一下详细设计解决局部问题的两种特殊情况:框架未确定之前的技术预研,案例1、3属于这个情况;框架确定与否都不影响的局部问题求解,案例2属于这个情况。一般认为详细设计是概要设计之后的,大部分情况确实如此,但通常我们进行概要设计之前还很可能需要针对某些需求点进行技术预研,这些技术预研是需要用详细设计的程度来进行。

需要补充说明的是:某些技术难点的设计,通常仅仅靠顺序图是搞不定的,甚至不能用顺序图,我还会用到类图、对象图、活动图和状态机图等等,类图用到的机会最大,你看看23设计模式,设计思路基本上都是用类图来表达的。UML图仅仅是一种工具,前文提到的“实践二:代码就是设计”和“实践三:Demo就是设计”,对于难度高的详细设计是经常需要用到这两招的。


7.5 需要从详细设计中提炼出需要全局考虑的内容

前文提到”详细设计是架构设计的延续”,其实还需要补充的是“详细设计需要持续完善架构设计”。详细设计过程中,我们会发现很多共性的内容,需要提炼为整个程序需要遵循的设计规范。下面是一些例子:
1)用户体验设计;(下一篇再详细介绍)
2)输入合法性判定;
3)批量数据的传输约定;
4)实体类的生命周期;
5)逻辑类的生命周期;
6)并发冲突的处理原则,包括判定办法、提示办法;
7)连接打开、关闭原则;
8)采用事务的原则;
9)异常处理机制;
10)日志记录机制;
……


8.6 详细设计小结

对于MIS类型系统来说,架构设计和数据库设计做好的前提下,详细设计的难度其实是比较小的了,你可以用顺序图来完成设计,注意做到需求驱动详细设计,注意要满足架构设计和数据库设计。不过不少MIS会有一些特殊的需求点,我们需要识别出来并想清楚应对办法,某些特殊的需求点还需要进行前期的技术预研。
如果你做的不是MIS类型的系统,而是设计难度很高的软件,比方说技术含量很高的CAD软件、人工智能很牛逼的某些家用游戏,要解决这些软件的详细设计,你需要设计模式、工程绘图、数学、物理、人工智能等很多知识支撑才能搞得掂了!




8)用户感觉好才是真的好——用户体验设计

8.1 从“余额宝是吸血鬼”说起——用户体验设计的重要性


某人写了一篇文章,说余额宝是吸血鬼,要取缔余额宝!

我大吃一惊,决定认真研究一下这篇文章,但愣是没有看懂!里面无非是说余额宝是银行的吸血鬼,会害死银行,害死金融市场之类的云云,反正没有看懂。我就纳闷了,我们把钱放到余额宝,每天赚取几块钱,跟你文章说的内容有毛关系?!你银行收费多,利息低,存取钱麻烦,我干嘛要将钱放到银行发霉呢?

这个事件跟用户体验设计有关系吗?我相信你已经有感觉了,请继续听我道来。

公司 A 开发的一个软件一直很好卖,但它的竞争对手公司 B 开发了另外一个更好用的软件,用户很喜欢。很快公司 A 的软件销量直线下降,为了挽回颓势,公司 A 请了某人写一篇文章“恐吓”用户,说一大堆用户看不懂的话,比方说:公司 B 的软件不面向对象,安全漏洞多,会吃掉内存,会损耗CPU等等。你估计用户看了这篇文章后会怎样?我估计用户会多买两套公司 B 的软件压压惊!

无论是银行还是余额宝,都为顾客提供一种资金投资的服务,但余额宝的用户体验比银行好多了,所以顾客会做出自己的选择;同理,软件给用户的感觉好,能带来实际价值,用户自然就会选择这个软件,用户是不会计较你用什么开发语言、数据库,还有用了多少种设计模式的。


我们来一个角色扮演,假设你是用户,你将会花钱买一套软件,你的购买标准是?

调查,你会选择怎样的软件?

A)你是软件开发狂热者,他比较偏好架构设计良好的软件,他甚至想得到设计文档和代码。对于软件,功能基本能用就可以了,有点错误也可以忍受。
B)你是唯美主义者,他要求界面要爽心悦目,功能能用就可以了,操作麻烦一点也没有关系。
C)你是实用主义者,界面不需要很花俏,关键是软件要容易上手,操作要方便,能高效地帮助他完成日常工作。

我想你应该不会这样变态选 A 吧?选 A 的话,恭喜你,你确实是软件开发的狂热者!

选 B 的朋友有木有呢?你是外貌协会的吧?

选 C 的朋友比较务实了,你会很珍惜你的每一分的血汗钱,软件需要物有所值,你才愿意投资!



8.2 什么是用户体验设计?


先说说什么是“用户体验”?

用户体验就是用户使用软件时给他的整体感受,而用户体验设计就是针对“用户体验”的设计。

其实要让用户有好的感觉,主要取决于以下三点:

1)软件能满足需求;

2)在1)的基础上,软件用起来很舒服;

3)软件的价钱是合理的,当然价钱 越便宜越好,最好是免费的。

我们这里谈的用户体验设计,主要是针对第1)、2)点来谈的。

如果客户和我们抱怨软件不好用,我们首先要检查的是需求是否满足了?如果满足了,那么至少可能打60分了。在需求满足的前提下,再进一步提升用户体验,就会让你的分数上升到80分以上。那有没有机会满分呢?通常很难的,除非你的软件是满足需求、很好用,并且是免费的!

是否满足需求,解决软件能不能用的问题;用户体验设计是否能更上一层楼,能解决软件好不好用的问题。


用户体验设计,体现了前文提到的“由顶而下”设计思路的体现,见下图:


图8.1 由顶而下的设计思路

说明一下:此图中“规划界面”这个活动的输入是”用例/用户故事“和”业务流程图“,但其实”业务概念图“也是需要考虑的,此图画出的是主要的先后关系。


对于用户体验设计,可能会有人第一反应是美工负责的事情,实际上美工仅仅是其中一部分而已,用户体验设计需要考虑以下三方面:

1)整体界面规划
2)统一界面标准
3)易用性设计

下面分别说明。



8.3 整体界面规划


有没有曾经试过客户向我们抱怨软件不好用,我们询问客户哪里不好用,客户一时半刻说不出来;在我们的耐心追问下,客户终于憋出一两点不好用的地方来,于是我们马上进行改进,但客户仍然说不好用;于是我们再次耐心的追问,客户又憋出一两点不好用的地方来……  周而复始,客户还是觉得不好用!

你觉得问题在哪?你可能要重新检讨界面的整体规划!

整体界面规划做的事情就是:规划软件需要什么界面,每个界面能做什么事情,每个界面之间是怎样关系等。这是用户体验设计的最关键、最核心、最重要的一环,这个做好了,基本上用户体验设计不会差到哪去,反之无论你在哪些细节上修修补补,很难在根本上改善用户体验。


我们仍然用前文的”考勤系统“作为例子,需求请参考前文,链接:http://blog.csdn.net/fireball1975/article/details/18967945

下图是前面出现过的考勤系统的部署图:


图8.2 考勤系统的部署图


红色箭头指向的客户端是“PC”客户端,我们要思考这个客户端的用户体验设计,我们要回答两个问题:

1)什么角色将会使用这个客户端;
2)这些角色通过这个客户端能做什么事情。

于是我们我们发现,”员工“和”领导“这两种角色都会使用这个客户端,他们分别通过这个客户端能做的事情有:

员工:

1)查看全部人的请假外出情况
2)提出申请
3)查看申请进展情况
4)修改申请
5)删除申请

领导:

1)查看待审批的申请
2)审批员工的申请

根据上述信息,我们可以规划出PC客户端的界面流:


图9.3 考勤系统PC客户端的界面流


小结一下整体界面规划的做法:

1)要熟悉需求。
2)在架构设计的基础上找出系统的客户端有哪些,这些客户端是指最终用户会接触到的机器,一般不需要考虑服务器端。
3)思考每个客户端上的用户有哪些,这些用户分别在这些客户端上需要用到什么功能。
4)画出每个客户端软件的界面流。如果觉得难度有点大,可先针对不同用户分别画他们的界面流,然后合并不同用户的界面流,思考界面的判断逻辑,使不同用户进去都能获得良好的用户体验,同时让程序工作量更小和弹性更好。


通常我们的项目当中是没有人专门做整体界面规划的,大部分的情况是程序员做出来怎样就是怎样的,但程序员做出来的界面用户体验设计,你懂的……

如果你是程序员,请按照上述思路改善的工作!

如果你是项目的管理者,请思考这些工作谁来做更合适?有些公司可能有专职的用户体验设计工程师,有些公司木有,那么你可以考虑让需求分析师、测试工程师来负责,或者是作为项目经理的你来亲自负责。负责这个岗位的同事至少需要具备这样的一个素养:就是能从用户的角度来思考问题!如果能同时具备技术功底,能设计出用户体验极佳而且开发工作量少的界面整体规划,这样就最完美了!



8.3 统一界面标准


统一的界面标准主要包括三方面:形象、文字和行为。

美工负责的事情主要就是形象方面的,包括有:(可能列不全)

1)整体风格:系统需采用一致协调的美术风格,使用户感觉是在使用同一个系统。如一致的色调、背景、图片等。
2)图片、图标、页面布局等方面的设计。
3)文字的样式、大小、字体等等。
4)界面上控件等各种元素的大小、颜色、风格等等。

文字方面主要是指文字的内容,与上述第3)有点不同。

软件中出现的文字大概分两类:

1)操作性、提示性文字,如:增加、删除、确认、取消等操作性文字,还有一些相关的操作提示。
2)专业性、业务性文字,如医院系统,系统中出现的药名、病名等专业性文字。

这两类文字都需要统一并且易于理解,例如我们经常犯的毛病:一个地方叫”新增“,一个地方叫”添加“,一个地方叫”增加“,这样就很不专业了。

现在说说行为方面要注意的事情:,举两个例子你就懂了。

例1:某些软件增加确认的提示很不明显,你点了一下”增加“,界面没啥反应,搞到你多点几下,后面发现增加了好几条记录了。

例2:某些软件删除之前没有提示,结果你一不小心就干掉数据了。

用户会在软件上做很多动作,常见的动作有:查看某条记录,查看某些记录,增加一条记录,修改一条记录,删除一条记录,删除一批记录等等。类似的动作,软件应该有合适的、易于用户理解的并且是一致的响应,这些都是对软件行为的设计。



8.4 易用性设计


我们分析一下互联网网站注册页面的易用性,以此为例子体验一下易用性设计。

注册网站是黏住客户的第一步,你打算如何设计才能让更多网友愿意注册呢?下面看看几个阶段的演化:

1)“皇帝女不愁嫁”的阶段

很久很久以前(其实也不是很久,10多年前吧),互联网刚流行的时候,注册网站是比较麻烦的,要看用户条款,要填一大堆信息,还要分几页来填,最后一页还因为网速问题出错,折腾死你!但当时互联网网站太少了,你不介意多尝试几次的。

2)“忽悠你进来再说”的阶段

你只需要填个账号,输两次密码,用户条款不需要看,你去打个勾就行了。

3)“简化到不能再简化”的阶段

现在有些网站,注册时输入用户名,但密码不需要输两次,一次就搞定了!希望你没有输错密码吧,呵呵。

4)“用户名都不需要输入”的阶段

本来以为3)的做法已经是无法再简化的了,但居然这么神奇,用户名都不需要输入,点个按钮就可以了!没错,这就是关联其他账号,比方说用QQ账户登录、用微信账号登录等等,如果你现在已经登录QQ,那么就可以一键关联账号并登录了!

大家为了争夺用户,注册这事情简化到令人发指的程度!


这仅仅是一个例子,系统中需要着重考虑易用性设计的地方还是很多的,例如:

1)首页。
2)经常被使用的界面,如登录、查询界面。
3)用来拓展业务的界面,如注册界面。
4)复杂的编辑界面。
5)带有运算功能的界面。
6)重要人物会使用的界面,如报表。
……



8.5 技术人员应该怎样对待用户体验设计

N年前,我作为面试官面试一位程序员,该程序员是来自竞争对手的公司的。我问他为什么离开原来的公司,他说:原来那个公司代码很不规范,很多 If Else,很多 Select Case,每一次遇到需求变化都需要去折腾,这些代码已经无法改下去了,我想到更规范的公司工作!
程序员追求进步是好事,但如果我告诉你另外一个让我们惭愧的事实,你可能不一定愿意加入我们公司了。这个让我们惭愧的事实就是:竞争对手的软件销量比我们的软件高多了,这是因为他们的软件好用,用户体验好!我们的软件更多是面向软件工程师,而不是面向最终用户。
如果这个事实还不足够让你震撼,那么和你的薪金挂钩,相信就会震撼到你的小心脏了!你的软件卖的好,你的薪金高,你能获得高额的提成,你会介意去处理那些If Else吗?还是喜欢去干程序结构良好,但用户体验很差,软件卖不出去,工资高不到哪的工作?
回到本文开始的那个例子,决定客户是否买软件的决定因素就是用户体验,而不是你的程序如何OO,如何用了多少种设计模式?

上述文字可能有些极端,并不是鼓励你只追求用户体验设计,而不需要关注软件的内部结构,而是希望作为技术人员的你,能更多关注一下用户体验设计。



8.6 用户体验设计小结

架构设计、数据库设计打造的是软件“内在美”,详细设计主要打造“内在美”同时也需要考虑“外在美”,而用户体验设计主要就是针对“外在美”的!
软件的UI是客户直接体验软件的地方,好的用户体验比追求新技术和追求漂亮设计更加重要,优秀的软件应该是既有外在美也有内在美的。当然我还要啰嗦一句,大部分用户是外貌协会的,不要企图用“某软件是吸血鬼”的说法来恐吓客户,让客户不买竞争对手的软件,只买你的软件噢!



9.持续提升设计水平


软件设计有无尽的可能性,绝对不是几篇文章或者是一本书就能帮助你升仙的,多实践多尝试才能帮助你更上一层楼。工作中的设计挑战可能不丰富,难度不够,你自己需要为自己多找一些案例来挑战,多写代码,多做总结,建立你自己的代码重用库。

如果你是公司的管理层,你可能不仅仅考虑的是个人能力提升的问题,而是更多地考虑让整个公司设计能力提升的问题,可能想到设计流程制度化、设计文档模板化等工作思路。公司领导要更多考虑需求积累、技术积累,打造公司的核心产品线,核心技术等,打造代码重用库、组件库等等,要达到一定的高度都不是靠爆发的,而是靠长期的积累。积累达到一定的层次,“后人”就可以利用“先人”的智慧达到更高的高度。我们这些现代人可能并不比古代人聪明,我们能干很多古代人不能干的事情,是因为我们利用了先祖为我们积累的大量文明成果。








已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页