在构建系统时,尤其是一些大项目实施的过程中,可以接触和学习一些高阶层面分析问题和系统架构的方法论, 如麦肯锡的解决问题7步法:定义问题、分解问题、排定优先级、制定工作计划、分析问题、综合分析、阐明观点;TOGAF的关键是架构开发方法(Architecture Development Method: ADM),业务流程设计方法、PMP项目管理流程等最佳实践和科学管理方法。
在完成项目规划和高阶论证之后就是系统具体实现的设计的,本文分享和探讨理解需求建立系统模型的部分方法和工具的初步介绍,因个人能力有限, 敬请指正错误。
系统设计的工作通常是业务需求分析师或系统工程师负责,业务需求分析师偏向于业务需求,系统工程师在要求业务分析和系统设计同时具备。当项目中存在系统工程师,通常就代表着有系统方案设计和评审环节,如果是BA负责,就可能会出现将业务方案设计和系统方案混淆并忽略系统设计方案的设计和评审,从业务需求模型直接进入功能详细设计。在这种场景下,开发人员也应提升系统设计的意识和能力,尽可能的从技术和非功能性需求(如扩展性、可维护性)方面补充系统设计。
要进行系统设计,首先要进行系统思维。
系统思维简单地说就是把某个疑问、某种状况或某个难题明确地视为一个系统,也就是视为一组相互关联的实体,将问题具象化为系统实体及其之间关系,建立相应的系统模型。
其它思维模式:批判思维(衡量某个说法的有效性)、分析思维(根据一套规律或原则进行分析)、创新思维等。
整体性原则是系统思维方式的核心。整体原则:每个系统都作为某一个或某些大系统的一部分运作,同时,每个系统中也都包含着更小的一些系统。整体原则要求从整体与部分、整体与环境的相互作用过程来认识和把握整体。
系统思维具体实施过程可以按照以下步骤进行:
关于系统架构及思维方面的介绍推荐阅读《系统架构:复杂产品的设计与开发》。
确定实体可以下面的顺序进行:
下面我们举例描述系统设计中实体确认初略过程。
采购寻源功能: 采购寻源是供应商管理系统中的子模块,供应商和采购方通过该流程对可能产生的交易进行前期的交易物的内容规格沟通澄清,达成意向价格。为物品采购提供供应来源。
采购寻源属于交易的范畴,应该交易系统的角度去思考。
从交易或合同的角度去理解最基本元素或者说实体包括:交易物、交易团体、交易类型、价格、数量。交易类型可以分为多头(买入)或空头(卖出)等。
寻源所指价格和具体交易的不同,类似于期货交易,约定的是某个时间和地点的价格, 不同的是寻源所得价格并不等同于交易,仅仅是一个意向。 两者都表达的是在一个特定场景下的价格(比如时间、地点、交易数量、 付款方式等等)。
价格的最终确定需要一个协商过程,需要报价对象来表示形成最终价格的中间价格。报价包含以下价格:采购方提出的价格-出价,供应方提供的价格-索价,两者的中间价、差价,价格协商的轮次等信息。
整体性思考,可以从以下角度考虑考虑:入口、出口、识别系统变化点、非功能性需求等角度考虑。场景的变化多样性需要按照规则和需要设定一些实际业务场景模板-寻源模板,最终生成价格后,价格会被后续的订单模块所使用,需要记录价格使用记录,对于产生价格数据需要有价格管理器负责管理价格生命周期,价格数据需要按照特定的分析场景-分析场景对价格进行分类形成价格目录(或分类)的概念, 对同一目录下的价格进行分析、比较和汇总,应该需要一个价格选择器接口负责实施价格分类的逻辑。
实体名称 | 含义功能 | 可能的设计模式 |
交易物 | 寻源过程协商价格对应的物品,可能是实物或者无实物的服务 | |
交易团体 | 参与寻源过程的组织或团体,包括买方和卖方 | |
场景/场景元素 | 场景代表一个上下文的,场景元素则是形成独立上下文的因素,通常以键值对存在。 | |
价格/价格场景 | 寻源最终输出、指定价格场景下生效的价格。 价格自身通常包括数字、币种、汇率。价格是价格服务的聚合根。 | |
寻源过程/寻源场景 | 对产生价格的流程的抽象, 定义了整个过程的完整步骤、规则等信息。寻源过程是寻源服务的聚合根。 | 工厂模式 |
报价 | 报价是产生最终价格的中间数据、报价通常包括出价、索价。 | |
报价处理器 | 从多分报价中确定最终的价格是业务核心规则、是变化点和扩展点,应提取单独的对象来进行封装并提供扩展性, | 策略模式 |
寻源模板 | 预先定义的场景。 | |
价格使用记录 | 价格的使用应得到记录和校验,保证价格的使用符合价格场景的限定。 | |
价格管理器/价格生命周期 | 价格从产生到失效的完整生命周期应进行清晰定义, 并由专门的管理器对象负责处理影响生命周期的事件和价格生命周期的改变。 | 发布/订阅模式;状态及模式等 |
价格目录/价格分析场景/价格选择器 | 在后续的价格使用或分析过程中需要将价格进行组合分类使用或分析,可以通过价格选择器对象 | 过滤器模式/组合模式 |
表1: 采购寻源实体清单
备注:面向对象的设计方法认为应该将对象的行为封装到对象类中,通过继承/组合等方式扩展。 对于复杂和易变的业务规则应抽象为单独的规则处理器类以隔离稳定部分和变化部分、规则处理器类的设计应使用扩展性设计,如事件监听器、过滤器、策略模式、状态机模式等来应对后续业务规则的变化。
图1: 采购寻源示例模型
使用模型图,来表示功能是设计关键方式,有以下意义:
系统需求通常可以抽象为以下的某种通用需求后再进行扩展:
应基于通用需求的领域模型进行完善并再次抽象为合适的模型形成模型库为后续使用。
领域模型是对领域(业务)内的概念类或现实世界中对象进行可视化表示,专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。
领域驱动设计是以领域模型为核心的软件开发设计方法。主要内容包括:领域驱动设计的设计语言和领域驱动设计架构
定义了领域驱动设计所涉及的概念。
领域: 一个组织所做的事情以及其中所包含的一切。当为某个组织开发软件是, 面对的就是这个组织的领域。
子域: 领域包含多个子域。
限界上下文: 语言层面的上下文边界。 一个限界上下文中的子域拥有共同的语言。(这是一种拆分系统、服务的思想,也是DDD的关键),一个限界上下文不一定只包含一个子域。
聚合: 聚合是一些实体为了某项业务而聚类在一起形成的集合,可以认为一个子域对应一个聚合, 一个聚合有一个聚合根。
聚合根: 聚合根:如果把聚合比作组织,聚合根则是组织的负责人,聚合根也叫做根实体,它不仅仅是实体,还是实体的管理者;聚合根是某个子域的唯一入口。
实体\值: 聚合内对象
领域驱动设计以业务领域为核心,建立得到领域专家高度认可和共识的领域模型,保证系统设计能充分理解和实现业务领域的需求。聚合的内容是领域业务。
领域驱动设计任务系统的核心和难点是业务,应以域的概念对业务进行充分理解和聚合,相关业务的代码和数据应高度聚合在整体内(子域)。相比较的就是以功能聚合的系统设计。 以订单为例, 传统功能性设计会存在一个订单团队去支持各种类型如低耗、固定资产、服务的订单,领域驱动设计的理念则是由具体业务的实施团队将订单放置于自身业务的场景下去负责订单方案的设计和功能实施。
现实项目中往往需要综合模块化和领域驱动设计的理念去进行设计,由模块化团队从功能角度思考功能框架的设计,建立通用框架。而那个功能的业务变化点转移到业务领域去思考和实施。要求模块负责人或系统整体负责人要正确的识别两者的边界。
推荐了领域驱动设计的一些架构实践。
图2: 领域层示意图
图3: 六边形模型
图4: 命令和查询分离设计模式
图5: 事件驱动设计系统模型
模块化、服务化、领域驱动设计三者都是将系统整体划分成部分的方法。
模块化和领域驱动设计都可以当做进行系统/服务拆分的一种方法。
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式是设计在编码阶段的语言,蕴涵的设计理念同样可以在系统设计阶段可以去使用。
分类 | 名称 | 使用频率 |
创建型 | 单例模式 | 常用 |
原型模式 | 常用 | |
工厂模式 | 常用 | |
建造者模式 | 低 | |
结构性 | 代理模式 | 常用 |
桥接模式 | 常用 | |
装饰者模式 | 常用 | |
适配器模式 | 常用 | |
门面模式 | 低 | |
组合模式 | 低 | |
享元模式 | 低 | |
行为型 | 观察者模式 | 是 |
模板模式 | 常用 | |
策略模式 | 常用 | |
职责链模式 | 常用 | |
迭代器模式 | 常用 | |
状态模式 | 常用 | |
访问者模式 | 低 | |
备忘录模式 | 低 | |
命令模式 | 低 | |
解释器模式 | 低 | |
中介模式 | 低 |
表2 设计模式列表
设计原则:
以上原则的说明是从编码角度取阐释, 在系统实体和模块的关系设计上同样适用。
有关设计原则和设计模式相关内容参考《设计模式-可复用的面向对象软件元素》及相关书籍。