软件系统架构可以理解为是软件程序的架子,和现实中的书架相比有异曲同工之妙,这个架子上有很多大大小小的格子,每个格子里都可以放固定种类的程序。架子有大有小,大的需要花费点去做,小的轻便快捷。
架子的大小是由做设计的设计师决定的,设计师根据客户的需求设计大小,假如放置的空间大,且需要承载的东西多,那么就往空间大的方向设计,能容纳更多的东西,能放置各种不同类型的程序,反之则做小一点,又快,又轻。
一,承载力。
二,可扩展度。
三,易用性。
四,可伸缩力。
五,容错力以及错误的感知力
构建一套复杂系统,我们把整个系统划分成若干个层次,每一层专注解决某个领域的问题,并向上提供服务。这样的抽象做法,让复杂的事务变得更加清晰有序。有些层次并不一定是横向的,也可以是纵向的,纵向的层次贯穿其他横向层次,称为共享层。如下图:
一个中小型的Spring Web应用程序,我们一般会设计成三层架构:
Linux操作系统是经典的分层架构,如下图:
TCP/IP协议栈也是经典的分层架构,如下图:
分而治之也是应对和管理复杂性的一般性方法,下图展示一个分治的思维流程:
这是我2015年在思考Unity3D手游项目开发整体流程时,用分治法抽象出来的对整个问题的分解。我首先把code编码作为主中心,再把除了code的以外的事拆分成打包发布,资源部署到外网与检测,版本控制,项目管理平台。再对拆分出来的大块问题,进行细化,分解到具体的某个小问题。
对于一个无法一次解决的大问题,我们会先把大问题分解成若干个子问题,如果子问题还无法直接解决,则继续分解成子子问题,直到可以直接解决的程度,这个是分解(divide)的过程;然后将子子问题的解组合拼装成子问题的解,再将子问题的解组合拼装成原问题的解,这个是组合(combine)的过程。
下图是建筑的演化史,在每个阶段,你可以看到设计的影子,但如果时间线拉得足够长,演化的特性就出来了。
总结下,我们上文中我们强调了抽象思维在架构设计中的重要性,以及抽象思维的几种用法,包括分层思维,分治思维,以及演化思维,他们帮助我们在抽象的架构设计中起到了很好的作用。、
分层的思维方式,先确定架构的层级,如下图。
把整个项目分成五大层级,网络层,数据层,资源层,核心逻辑框架层,UI层。
再分层。如下图:
网络层来说,进行分而治之,如下图:
各个模块的拆分原则:
数据表 -- XLS导为二进制文件还是Json或其他格式,读取接口和解析接口的定义。
UI层 -- 使用NGUI还是UGUI,界面基类,界面管理,输入事件封装,自定义通用组件基类,自定义各类通用组件。
外部资源管理 -— 是否使用AssetBundle,AssetBundle资源分类,AssetBundle资源间的依赖关系,加载与释放AssetBundle的管理,AssetBundle加密。
AI层 -— 使用状态机还是行为树或者其他,状态机或行为树接口实现,AI可视化工具,AI扩展接口。
地形地图 -— 地图是2D还是3D,场景编辑器的结构,是否需要Mesh合并,场景内的大小物件区别对待,大地形在游戏里该怎么逐步显示,是否要划分区块。
寻路与网格 -— 使用A星还是跳点算法或者其他,使用网格栅格还是三角网格,长距离寻路的解决方案,地图数据管理。
常用库 -— 时间函数,数学函数,数字变量加密封装,坐标转换函数,Debug调试工具,各大逻辑系统通用工具等等。
角色行为控制 -— 人物移动处理方案,摄像机的碰撞检测,动画特效编辑器,技能编辑器,行为流的建立。
2D动画控制 -— 动画组件封装,2D动画的制作流程,2D图合并为图集。
实际工作中,我们对层级和模块逐个攻破的同时,也进入架构演化模式。一开始的做的架构中某个部位的并不适合,或需要改善,在后面的工作中,修复和完善架构是演化的重要步骤。
在不断编写完善架构的过程中原本抽象简单的架构,开始复杂化。虽然每个模块都在有条不紊的进行中,但也会不断冒出各种各样不适应或者不符合实际需求的问题出现,我们需要及时跟进演化内容。去除、重构或者改善,前面由于各种原因而导致的错误的理解。
最后架构设计的文档要及时跟进完善,在抽象的过程中,我们需要整理和记录整个过程,以便为今后在完善时能够一下子翻阅到并记起当时在架构时所考虑的各方面问题的原因。