架构与设计
架构是什么?我个人想得很简单,其实就是架子的结构,譬如动物都有属于自己的骨架,房子也有自己的结构框架等,这些都属于现实物体的架构;从这些看来其实架构会影响最终物品的形态和质量(人的骨架那出来的肯定是人形)。这个对于程序来说也是一样,在这个二进制的世界中,程序员扮演着上帝的角色,为这个世界创造不同的东西。那么,这就需要我们思考如何合理地进行设计物体,其中架构作为物体的根本显得特别重要。
很多人都认为架构设计必须是一位经验老道的程序员才能做好的事情。这只能算是说对了一半,经验丰富的程序员能肩负设计重任,最主要是他对计算机技术相对了解,更能把握一些实现细节,让设计更加合理。但不是所有经验丰富的程序员,都能设计出一个出色的架构。对于架构设计来说,丰富的计算机知识只是要求的一部分,更多的要求是需要你是一位业务专家。
都说不懂业务的程序员不是一名好程序员。确实是这样,如果仅仅追求代码和算法上的极致,在业务上不假思索,任人摆布的话,对于程序设计是很不利的,至少对于程序架构的可预见性就会变得很低。甚至在业务需求与程序设计发生冲突时,往往会偏侧于当前的设计,缺乏对业务的思考。所以很多时候我们会看到程序员跟产品经理开撕,这个需求不能做,那个需求调整需要很长时间。其中有一部分问题就是因为架构设计不合理导致的。
在架构设计范畴中个人觉得对于业务的理解和经验积累,相对于技术的积累而言是更加重要的。如果要提升设计的能力,我们就应该要争取成为各种业务专家。
没有最好,只有最适合
有个朋友经常会发一些代码过来,然后问我:“阿杰,帮我看看这样的设计好不好?” 面对这个问题,我真的是一脸懵逼,同时也有点尴尬。一来我不知道需求是什么,没有办法评估这样的设计好坏,二来其实架构设计的核心还是方法论,不同的人所思考的侧重点不一样;因此,设计出来的框架也会不一样,所以,并没有好不好的说法,只有符不符合你的需求。
然而很多人都会崇尚技术大牛所谈到的架构设计,希望在自己设计时模拟大牛们的做法。但这需要投入精力去研究和了解,每种设计下必定会有属于自己的设计理念和侧重点,这个时候就需要我们深入分析它的使用场景以及该模式下的一些特定和不足。如果做不到这样,那么你的模拟纯属生搬硬套,不仅没有发挥架构的效果,反而影响程序的性能和质量。
架构设计 != 设计模式
设计模式是对某一类问题提出的具体解决方案,例如MVC主要是降低视图与业务逻辑的依赖,观察者模式则主要是解决消息投递问题等等。在架构设计的框架设计阶段对于一些重点功能模块会根据实际需求来考虑使用的设计模式。例如:一个带有即时通讯功能的App,用户消息接收可能会发生在App的各个界面中,那么就要考虑使用观察者模式,让每个界面监听接收消息的通知,然后进行提示处理。
学好设计模式就一定能做好架构设计?其实这是两个不对等的概念,它们虽然都是一种思维方式,但是设计模式指具体问题的解决方式,而架构设计则更偏向于多种问题的分析整合,其中包括解决方式和规范约束。
设计思维的养成
首先我觉得要戒掉一个坏习惯,就是一接到任务就急着开始编码。不管你是不是这个项目的技术负责人、主程、还是团队中的一名开发人员,首要做的事情就是思考如何实现需求。对负责的内容进行前期的设计,并且产出一定的设计文档,规范标准等。如果已有架构设计文档,则要通读文档,了解其中的思想以及要注意的地方(例如文档中提到的约束),然后在其基础上和理念上设计自己的内容。
同时,还需要培养自己的思维不仅仅是聚焦在开发层面上,要考虑在需求变更时、后续维护时乃至重构时该框架的一些措施。然后配合软件设计中的高内聚低耦合原则来优化一些设计细节。
当前期的设计完成后,则开始要进行概要设计了,例如模块核心类型结构。我个人比较习惯使用类型声明的方式来对程序整体进行构造,这过程中不带有任何逻辑的实现,但是能体现类型与类型之间的关系,用于快速调整一些不合理的地方或者在设计阶段没有考虑到问题,然后在对架构设计进行修订。
设计思维的养成是循序渐进的,它需要我们在每一次的工作中培养起来自己对设计过程的感觉。而这种感觉需要大量的经验和知识去把它支撑起来,并且在这个过程中不断地进行完善。所以并不是死记硬背或者按照套路就能够做好架构设计的工作,平时一定要有意识地去培养。
事例实践
下面我想以《网易新闻》的iOS客户端作为例来展开说明一下我是怎样进行一个架构的设计(这里要说明一下:我并不知道网易新闻客户端的实际设计是怎么样的,下面只是借助它来说明架构设计的一些主要元素,不会具体到一些很详细的设计内容),我总结了几个步骤:
1. 需求分析
首要任务就是清楚自己需要实现什么,未来的业务方向又是怎么样的?对于新闻客户端来说,重点功能毋庸置疑就是提供用户阅读新闻的途径,了解或者关注一些前沿资讯。至于《网易新闻》未来会发展成怎么样我无从得知,也许会有内容变现的可能(毕竟最近又聊起来了这话题)。那么基于这些需求,可以从中提取一些关键词,如下面脑图所示:
关键字的提取有利于需求的分析,方便日后在划分功能模块和设计时可以起到指导作用。
2. 规范与约束
很多人一旦接到需求,第一个想法就是开干,尽早把代码码出来。我能体会想从编码中获取快感的感受,但是在编码前一定要为自己的设计进行一些限定和说明,否则往后的编码可以说是混乱的。这个时候就需要借助结构框图来描述我们的设计和组成,下面是我为新闻客户端设计的一个框图:
因为是客户端的设计,所以这里采用的是流行的MVC设计模式来对程序进行了分层。同时也基于需求的关键字对系统模块进行了划分,如资讯系统、用户系统、钱包系统等。基于这个图我们可以清楚知道什么东西需要以视图形式展示,需要定义什么实体,以及那些功能属于那个系统模块等等。
除了设计图表,我们应该还要为图表进行一些文字说明。主要说明是基于什么原则或者以什么基础设计的,并且要说明其中的一些约束。例如上图的设计是对需求分析得出重点功能在于资讯和用户,然后基于App的传统三层设计得出来的。在这个设计基础上需要遵循下面约定:
- 不能跨层访问和操作
- 功能模块之间的数据实体不能带有业务功能。
- 业务管理器不能直接对接数据模型,必须通过数据管理来进行操作。
我个人觉得这个步骤是体现整个架构灵魂的一个重要步骤,它定义了架构的形态和内部机制,是一个架构往后能否进入良性发展的基础。
3. 细化与评估
框架整体设计完成后,接下来的工作就是对框架进行细化和评估。例如上图的资讯系统需要为它整理核心流程。其中用户浏览资讯流程如下:
补充核心流程的作用在于贯穿整个架构,让各个模块串起来形成一个真正整体。至于要用时序图还是流程图描述,视具体情况而定。如果需要体验多端协作的流程可以使用时序图或者多泳道流程图,如果重点体现内部流程则使用流程图。例如用户对资讯的评论流程则主要体现内部处理,则使用流程图:
接下来结合核心流程来对资讯系统进行细化:
最后对细化的架构进行一个评估,这个评估会从扩展性、灵活性、兼容性以及可移植性方面进行。那上面的细化后的资讯系统来看,用户系统直接是对接资讯的视图层,从设计上来看是降低了对用户系统的依赖。然后各个层次间的界限也相对分明,不存在跨层访问的现象,使系统有更强的可扩展性和灵活性。
4. 技术选型
前期设计完成后,就需要对框架进行技术选型。如架构中采用MVC分层,那具体是要使用传统的MVC模式,还是MVVM,还是MVP等等。在这里我个人觉得传统的MVC模式就可以胜任,主要是考虑控制器层次已经做了进一步的业务细化,因此在C这一层中的代码量会减少很多。
然后还有数据存储需要使用什么方式,由于客户端的数据存储只用于简单的缓存记录,不设计复杂的查询功能。因此可以考虑使用文件方式进行存储。
类似上述的技术选型工作,往往要根据实际的需求来确定所选的技术。如果有多套解决方案,则需要评估其性能、稳定性还有易用程度方面的因素。有时候还需要结合工期来考虑是否使用第三方解决方案还是自主研发。
5. 框架搭建
终于到了编码前的最后一个阶段。在这里我们就需要对前面做的设计工作做一个转换,将其使用程序的语言来进行描述。这个时候我们需要借助类图来完成这个过程。如下图所示:
从类图来看,基本跟之前的设计图一致。这个很重要,如果设计出来的类图跟其他层次图、框图出入很大,那很有可能在转换类图的过程中出现了一些新的设计思路,这个时候要审阅转换前后究竟是那部分出现问题,然后再进行修订和同步。
6. 推进与支持
架构设计其实是一个持续的工作,在进行前期设计工作完成后,就要进入到后期的推进和支持工作。具体的操作是在团队内部讲解你的架构设计相关的东西,让所有人了解你的设计思路,然后沿着你的思想指导进行后面的开发工作。同时,在推进的过程中会难免遇到实际的问题,这个时候就需要作为架构设计的你去进行分析和评估,然后选择比较可靠的解决方案来完善之前的设计。
架构设计对我的影响
貌似架构设计已经成为了我工作乃至生活中不可缺少的一部分,我觉得它并不只属于程序设计,更像是一种艺术创作的思维。平时的我喜欢将一些天马行空的想法具像化到某个程序当中,这个过程就涉及架构的设计。而每次都让我都感到兴奋,因为在这个过程里面,我总能发现一些之前从未了解过的东西,也能让自己觉得在不断地进步。