摘要:
概要设计和详细设计,可能是最开始听说的设计,但后来发现如果局限在这两个设计的框架下,可能会有诸多不顺,我们需要架构设计、数据库设计、模块设计和用户体验设计,本文主要分享架构设计,此文有点长,所以分拆为上下两篇,下篇为你分享:在”需求驱动“如何做出初步架构设计、如何逐步细化这个设计、分布式与单机系统架构设计的区别等。
大纲:
1.什么是优秀的设计?
2.优秀的设计能节省项目工作量3.优秀设计从分析需求开始4.软件系统不是木桶型的5.软件设计的“大道理”6.规划系统骨架——架构设计7.打造系统的底蕴——数据库设计8.细节决定成败——详细设计9.用户感觉好才是真的好——用户体验设计10.持续提升设计水平
本文章是系列文章之一,如果你还没有看过之前的文章,建议先看完前面的文章再看本篇,这样效果更好。
6.规划系统骨架——架构设计
6.5 逐步拆解架构设计
需求驱动设计
有这样的一句话:不以结婚为目的的谈恋爱是耍流氓!
这句话与软件设计有什么关系呢?很有关系呢!因为有另外这样的一句话:不以解决需求为目的软件设计就是耍流氓!
所以如果不想被人家说你耍流氓,你需要了解需求,需要“需求驱动”地思考设计问题。
前文我们从需求中发现了四个设计点,一起来回顾一下:
1)用例图中提到,员工可以通过移动设备提出请假或外出申请,领导可以及时收到审批的提醒。那么我们应该如何设计“即时了解”和“及时收到提醒”呢?解决方案可能有:短信提醒、邮件提醒、或者两者同时提醒。
2)需求中要求员工可以通过移动设备提出申请,领导也可以通过移动设备完成审批?我们要思考,为什么需要移动设备完成这些工作呢?什么情况下才需要通过移动设备完成这些工作呢?我们的解决方案是怎样呢?通过短信、手机上网,还是通过手机的APP来搞定?
3)请假申请和审批流程,跟流程相关的都可以扯到“工作流”。工作流可以是一个很“恐怖”的话题,你打算做一个"死"的工作流,“半死不活”的工作流,还是“全活”的工作流呢?你打算从零开始做,还是买一个工作流引擎呢?
4)权限要做成重用已经是有一定难度的,同时还需要考虑与工作流的结合,还要考虑工作流也可以做成重用,难度很高啊!那到底要不要考虑做成重用,并且权限和工作流能结合起来呢?
补充说明一下工作流:
1)死的工作流:就是代码写死的(hard code),数据库设计也是死的,流程或表单有任何变化,都可能需要改代码和数据库设计。
2)半死不活的工作流:部分地方写死,部分地方是灵活的,能适应部分需求变化。
3)全活的工作流:代码和数据库设计等都是灵活的,能基本适应流程及表单的变化,不需要修改代码或数据库设计,只要配置一下就可以搞定。
没有任何工作流技术积累的情况下,要做到“全活的工作流”是很高难度的,一般不要在当前项目中就定下这样的设计目标,基本是实现不了的。可以分阶段来做,先写“死”,然后“半死不活”,最后才追求“全活”。
初步架构设计(第一层拆解)
我们再次回顾一下,什么才是优秀的设计?
我在前文中提到,一个优秀的设计应该具备以下特点:
1)优秀的设计都是需求驱动的,不熟悉需求就做出来的设计是不靠谱的;
2)优秀的设计应该是当前团队能理解能实现的,太超前的设计项目团队做不出来,这个设计只能是摆设;3)优秀的设计应充分考虑当前各种限制条件,适当做出平衡,能保证达成项目的目标:4)优秀的设计能尽量降低项目的整体工作量,让整个项目更加可控。我们尝试一下,尽量按上述标准来完成这个设计吧!
我打算用 .net(开发语言采用 C#) 及 SQLServer 来开发这个系统。
你可能会问,为什么你选择这个开发语言和数据库?这些不是需要论证,需要做方案选择的吗?
我们不是搞理论或学术研究,一个真实项目的情况是这样的:你接手项目时合同已经签下来,合同中会规定用什么技术框架的,包括开发语言与数据库,一般不会不定下来的。而定下来的技术框架,一般就是你们公司最熟悉的那种,而你接手这个项目,一般是熟悉这个技术框架的。公司不会这么傻,选一个自己公司一点都不熟悉的技术框架来完成项目,客户更加不会这么傻选一个不懂这个技术架构的软件公司,你的上司也不会这么傻找不熟悉这个技术架构的你来负责这个项目的设计。
一个系统到底用.net好一点,java好一点,PHP好一点?这些其实没有定论的,一般来说就是你熟悉哪个就用哪个!哪个你最有经验最有成功案例就用哪个!针对具体一个项目做架构设计时,不能脱离具体的技术框架,要先确定你的开发语言、数据库种类等。架构设计要从物理设计的深度来思考,而不能仅仅是理论设计或者是逻辑上的设计,否则又会犯了太空洞的毛病(即“放之四海而皆准”的毛病)。
以下是初步的架构设计,这个设计并不是怎样“惊天地泣鬼神”,仅仅是我觉得我们能做到的也能应对需求的一个设计。
图6.6 初步的架构设计
图中标记出来的1、2、3、4,分别对应对前面的设计关注点1、2、3、4。此图对设计关注点1、2考虑得稍微具体一点,而对于设计关注点3、4仅仅是一个初步的考虑,因为当时我们工作流的技术积累还比较初级。
需要特别说明的:请留意“智能手机”这个客户端,图中写的是操作系统用WindowsMoble,这是一个以前的设计,在现在看来是不合适的,现在用这种操作系统的手机几乎不存在了。需求中提到要求使用移动设备完成相关工作,那么我们就需要思考是什么移动设备呢?移动设备上需要什么操作系统?需要安装什么软件等等?这些我们都需要考虑。
小结一下进行初步架构设计的要点:
1)我们的系统大部分会涉及到多个客户端及服务器,我们需要思考我们的系统需要怎样的客户端及服务器,思考这些设备上面需要安装怎样的操作系统、平台、软件等,思考这些设备需要怎样的硬件配置,如CPU、内存、硬盘大小等等。
2)我们需要思考这些客户端及服务器之间的物理联系方式,例如:是局域网方式、互联网,还是两者都支持?是HTTP或是HTTPS?等等。
3)这些设备上我们需要开发什么软件、数据库等?例如:图6.6中需要我们需要开发的东西有:Web Application、工作流定义用的客户端软件、三个数据库。架构设计其实就是划分系统的各部分及各部分的关系,这些内容其实就是我们整个系统的第一次的各部分的划分,而各部分的关系我们可以通过图6.6大致可以了解。
继续深入拆解(第二层拆解)
图6.6已经从硬件配置、软件各部分的划分、数据库的规划等方面描述了本系统的初步架构,当然这个架构还是太粗了,我们还需要继续深入思考,请看下图:
图6.7 架构设计的进一步思考
这个系统至少有5个需要我们开发的部分,每一个部分都需要更进一步深化设计,下面我们以Web Application为例子,继续深入设计!请看下图:
图6.8 Web Application的设计
我们规划 Web Application 的内部架构时,除了考虑内部各部分之间的关系,也需要考虑内部所划分出来的各部分,有哪些是需要和外部交互的?图6.6中表示的各部分关系还比较粗,我们还需要继续细化,请看下图:
图6.9 系统各部分的关系
当我们逐步细化设计的时候,我们很可能会发现之前初步架构设计不合理的或遗漏的地方等等,留意图6.9中红色的部分,这是之前没有画进去的内容。这个图已经更进一步细化设计了,但我们仍然有很多问题未解决,请看下图:
图6.10 更多的更具体的设计问题
图6.10与图6.9的区别就是多了黄色的部分,请思考这三个问题:
1)权限设置的UI如何考虑? 用户管理、权限管理的UI可考虑设计成可重用的。 界面可以是独立的,也可以“嵌入”到别的系统中。 2)工作流如何设计? 还需要对工作流进行进一步的抽象。 考虑清楚工作流的对外接口。 考虑清楚数据库设计。 3)图形定义客户端软件如何设计? 图形平台自主开发,还是利用第三方的? 数据如何保存到DB中?
除了上述这些问题和思考,还会有更多的其他问题,软件设计是充满挑战的工作!
设计初期的问题可能比较朦胧比较大,但随着设计的深入,问题会越来越多,问题也会越来越具体。有时候你会觉得怎么越深入设计,发现的问题越多,这是正常现象,而且是好事!如果没有发现问题,这往往不是真的没有问题了,而是我们不具备发现问题的能力了,这是相当可怕的,要小心留意不可轻敌噢!
图6.6后我们连续进行了多步的设计拆解,这里小结一下:
1)系统需要开发什么软件和数据库等,这些是第一次对系统各部分的拆分,姑且这叫”第一层的拆解“,接下来需要继续拆解。
2)继续拆解时可参考分层架构,但需要拆分得更加具体,不要犯”放之四海而皆准“的毛病。这个层次的拆解,姑且叫“第二层的拆解”。
3)除了规划好内部各部分的关系,还需要规划内部的各部分与外部之间的关系。
4)在拆解的过程中,问题会越来越多,也会越来越细,这是正常现象,也是好现象。
5)拆解过程中也可能会发现之前初步架构设计中不合理或遗漏的地方,请马上调整;有时候甚至会发现之前的设计完全不对,那么就要有勇气推翻重做。
6)“第二层的的拆解”结果有可能是组件(Component)、代码包、某个分层等等,可能是“物理分拆”也可能是“逻辑分拆”。那么“第二层的拆解”要多细才合适呢?其实很难有固定的标准,给一个简单标准作为参考:如果再拆解下去下一步的拆解就到类了,那么就可以认为目前的拆解粒度比较合适了。细化到类的拆解,可以在模块设计(详细设计)中再进一步考虑。
说明一下“物理分拆”和“逻辑分拆”:
物理分拆:物理分拆就是物理上是独立的部分,有可能是exe、dll、数据库文件等。图6.6中将系统分拆为5部分,分别是Web Application、流程定义用的客户端软件以及三个数据库,这就是物理分拆;我们对Web Applicationi继续分拆时,图6.8中的日历控件是物理分拆,这个控件将通过二进制的方式供程序其他部分调用,而这个控件将来也可以供其他系统使用。
逻辑分拆:代码包、某个分层这些往往是逻辑分拆,物理上它们不会编译成单独的一部分,而是被整体编译进软件当中。
“第二层拆解”的目的除了更加方便我们设计出系统,另外一个重要目的就是做系统的重用设计。如果是“物理分拆”,就可以做到二进制重用;如果是“逻辑分拆”,那么只能做到源代码重用。这些重用不仅仅为当前软件服务,还可以为将来及其他软件服务。
6.6 分布式系统与单机系统的架构设计
分布式系统可能有很多定义,有些资料可能也说得比较炫,文章这里提出这个说法不是用来“抛书包”的,这里也顺便说明一下:本文中提出的一些概念(例如:第一层拆解、第二层拆解、物理分拆、逻辑分拆)是为了更加方便说明问题而已,大家没有必要去互联网上搜索这些名词的定义。
我们开发的东西只需要安装在一台电脑上,这个软件就能工作,这就是单机软件,例如Office软件、Photoshop软件等;但分布式系统往往需要我们在多台设备上部署,各部分需要联调后,整个系统才能正常工作。
文中用到的案例是分布式系统,分布式系统如何做架构设计,相信你已经有一些体会了。单机系统的架构设计看上去似乎更简单一点,因为它不需要做“第一层拆解”,直接就是“第二层拆解”。其实不一定的,因为单机系统的“第二层拆解”往往是很复杂的,单机系统往往有特殊的高科技的算法、有独特数据存储格式等等,你可以设想一下,你能完成Office的架构设计吗?还有Photoshop的架构设计?
6.7 架构设计小结
架构设计是高难度、高技术含量的活,我觉得很难写出一本秘籍,你看了后就能应对大部分软件的架构设计。如果我们不精通业务,不精通技术,没有丰富的设计经验,很多设计我们将会束手无策。
小结一下分布式系统的架构设计要点,单机系统也可以参考:
1)我们的系统大部分会涉及到多个客户端及服务器,我们需要思考我们的系统需要怎样的客户端及服务器,思考这些设备上面需要安装怎样的操作系统、平台、软件等,思考这些设备需要怎样的硬件配置,如CPU、内存、硬盘大小等等。 2)我们需要思考这些客户端及服务器之间的物理联系方式,例如:是局域网方式、互联网,还是两者都支持?是HTTP或是HTTPS?等等。 4)思考系统需要开发什么软件和数据库等,这些是第一次对系统各部分的拆分,姑且这叫”第一层的拆解“。 5)继续拆解时可参考分层架构,但需要拆分得更加具体,不要犯”放之四海而皆准“的毛病。这个层次的拆解,姑且叫“第二层的拆解”。 6)除了规划好内部各部分的关系,还需要规划内部的各部分与外部之间的关系。 7)在拆解的过程中,问题会越来越多,也会越来越细,这是正常现象,也是好现象。 8)拆解过程中也可能会发现之前初步架构设计中不合理或遗漏的地方,请马上调整;有时候甚至会发现之前的设计完全不对,那么就要有勇气推翻重做。 9)“第二层的的拆解”结果有可能是组件(Component)、代码包、某个分层等等,可能是“物理分拆”也可能是“逻辑分拆”。那么“第二层的拆解”要多细才合适呢?其实很难有固定的标准,给一个简单标准作为参考:如果再拆解下去下一步的拆解就到类了,那么就可以认为目前的拆解粒度比较合适了。细化到类的拆解,可以在模块设计(详细设计)中再进一步考虑。
软件架构设计博大精深,上述仅仅是一些规律的简单总结,希望对你能有一点点帮助。
本文是系列文章的其中一篇,要做软件设计师一点都不简单啊,请留意后续文章!
如果本文对你有帮助,麻烦点一下“推荐”啦,谢谢!
作者:张传波
创新工场创业课堂(敏捷课程)讲师
软件研发管理资深顾问
CMMI首席专家
《火球——UML大战需求分析》作者
软件知识原创基地创办人